#include "AkaoParser.h" #include "engine/SoundManager.h" #include "common/File.h" #include "common/Logger.h" #include "common/TypeDefine.h" const u16 akao_pause_table[ 11 ] = { 0xc0c0, 0x6060, 0x3030, 0x1818, 0x0c0c, 0x0606, 0x0303, 0x2020, 0x1010, 0x0808, 0x0404 }; s16 akao_left_volume_table[ 256 ] = { 32640, 32384, 32128, 31872, 31616, 31360, 31104, 30848, 30592, 30336, 30080, 29824, 29568, 29312, 29056, 28800, 28544, 28288, 28032, 27776, 27520, 27264, 27008, 26752, 26496, 26240, 25984, 25728, 25472, 25216, 24960, 24704, 24448, 24192, 23936, 23680, 23424, 23168, 22912, 22656, 22400, 22144, 21888, 21632, 21376, 21120, 20864, 20608, 20352, 20096, 19840, 19584, 19328, 19072, 18816, 18560, 18304, 18048, 17792, 17536, 17280, 17024, 16768, 16512, 16256, 16000, 15744, 15488, 15232, 14976, 14720, 14464, 14208, 13952, 13696, 13440, 13184, 12928, 12672, 12416, 12160, 11904, 11648, 11392, 11136, 10880, 10624, 10368, 10112, 9856, 9600, 9344, 9088, 8832, 8576, 8320, 8064, 7808, 7552, 7296, 7040, 6784, 6528, 6272, 6016, 5760, 5504, 5248, 4992, 4736, 4480, 4224, 3968, 3712, 3456, 3200, 2944, 2688, 2432, 2176, 1920, 1664, 1408, 1152, 896, 640, 384, 128, 0, -1, -4, -9, -16, -25, -36, -49, -64, -81, -100, -121, -144, -169, -196, -225, -256, -289, -324, -361, -400, -441, -484, -529, -576, -625, -676, -729, -784, -841, -900, -961, -1024, -1089, -1156, -1225, -1296, -1369, -1444, -1521, -1600, -1681, -1764, -1849, -1936, -2025, -2116, -2209, -2304, -2401, -2500, -2601, -2704, -2809, -2916, -3025, -3136, -3249, -3364, -3481, -3600, -3721, -3844, -3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801, 10000, 10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881, 12100, 12321, 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376, 15625, 15876, 16129 }; s16 akao_right_volume_table[ 256 ] = { 128, 384, 640, 896, 1152, 1408, 1664, 1920, 2176, 2432, 2688, 2944, 3200, 3456, 3712, 3968, 4224, 4480, 4736, 4992, 5248, 5504, 5760, 6016, 6272, 6528, 6784, 7040, 7296, 7552, 7808, 8064, 8320, 8576, 8832, 9088, 9344, 9600, 9856, 10112, 10368, 10624, 10880, 11136, 11392, 11648, 11904, 12160, 12416, 12672, 12928, 13184, 13440, 13696, 13952, 14208, 14464, 14720, 14976, 15232, 15488, 15744, 16000, 16256, 16512, 16768, 17024, 17280, 17536, 17792, 18048, 18304, 18560, 18816, 19072, 19328, 19584, 19840, 20096, 20352, 20608, 20864, 21120, 21376, 21632, 21888, 22144, 22400, 22656, 22912, 23168, 23424, 23680, 23936, 24192, 24448, 24704, 24960, 25216, 25472, 25728, 25984, 26240, 26496, 26752, 27008, 27264, 27520, 27776, 28032, 28288, 28544, 28800, 29056, 29312, 29568, 29824, 30080, 30336, 30592, 30848, 31104, 31360, 31616, 31872, 32128, 32384, 32640, 16129, 15876, 15625, 15376, 15129, 14884, 14641, 14400, 14161, 13924, 13689, 13456, 13225, 12996, 12769, 12544, 12321, 12100, 11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000, 9801, 9604, 9409, 9216, 9025, 8836, 8649, 8464, 8281, 8100, 7921, 7744, 7569, 7396, 7225, 7056, 6889, 6724, 6561, 6400, 6241, 6084, 5929, 5776, 5625, 5476, 5329, 5184, 5084, 4900, 4761, 4624, 4489, 4356, 4225, 4096, -3969, -3844, -3721, -3600, -3481, -3364, -3249, -3136, -3025, -2916, -2809, -2704, -2601, -2500, -2401, -2304, -2209, -2116, -2025, -1936, -1849, -1764, -1981, -1600, -1521, -1444, -1369, -1296, -1225, -1156, -1089, -1024, -961, -900, -841, -784, -729, -676, -625, -576, -529, -484, -441, -400, -361, -324, -289, -256, -225, -196, -169, -144, -121, -100, -81, -64, -49, -36, -25, -16, -9, -4, -1, 0 }; s16 akao_wave_table[ 708 ] = { 8191, -8191, 16383, -16383, 24575, -24575, 32767, -32767, 0, 0, -2, 0, 32767, -32767, 0, 0, -2, 0, 8191, 0, 16383, 0, 24575, 0, 32767, 0, 0, -2, 32767, 0, 32767, 0, 0, -2, -8191, 0, -16383, 0, -24575, 0,-32767, 0, 0, -2, -32767, 0, -32767, 0, 0, -2, 0, 1280, 2530, 4813, 5790, 6625, 7297, 7789, 8090, 8191, 8092, 7793, 7302, 6632, 5799, 4823, 3728, 2542, 1293, 0, -1268, -2518, -3706, -4803, -5782, -6618, -7292, -7786, -8089, -8192, -8095, -7798, -7309, -6641, -5809, -4835, -3741, -2556, -1307, 0, 2561, 5060, 9626, 11580, 13250, 14594, 15578, 16180, 16383, 16184, 15586, 14605, 13265, 11599, 9647, 7457, 5085, 2587, 0, -2536, -5036, -7412, -9605, -11563, -13235, -14583, -15571, -16177, -16384, -16189,-15595, -14618, -13281, -11618, -9669, -7482, -5111, -2614, 0, 3842, 7590, 14439, 17370, 19875, 21891, 23367, 24270, 24575, 24276, 23379, 21908, 19898, 17398, 14470, 11186, 7627, 3881, 0, -3804, -7554, -11118, -14408,-17344, -19853, -21874, -23357, -24265, -24576, -24284, -23393, -21927, -19922, -17427, -14503, -11223, -7666, -3921, 0, 5123, 10120, 19252, 23161, 26500, 29188, 31157, 32360, 32767, 32369, 31173, 29211, 26531, 23198, 19294, 14915, 10170, 5175, 0, -5072, -10072, -14823, -19210, -23125, -26470, -29165, -31142, -32353, -32768, -32378, -31190, -29236,-26562, -23235, -19337, -14963, -10221, -5227, 0, 0, -39, 0, 0, 5123, 10120, 19252, 23161, 26500, 29188, 31157, 32360, 32767, 32369, 31173, 29211, 26531, 23198, 19294, 14915, 10170, 5175, 0, -5072, -10072,-14823, -19210, -23125, -26470, -29165, -31142, -32353, -32768, -32378, -31190, -29236, -26562, -23235, -19337, -14963, -10221, -5227, 0, 0, -39, 0, 2530, 4813, 6625, 7789, 8191, 7793, 6632, 4823, 2542, 13, -2518, -4803, -6618, -7786, -8192, -7798, -6641, -4835, -2556, 0, 5060, 9626, 13250, 15578, 16383, 15586, 13265, 9647, 5085, 26, -5036, -9605, -13235, -15571, -16384, -15595, -13281, -9669, -5111, 0, 7590, 14439, 19875, 23367, 24575, 23379, 19898, 14470, 7627, 39, -7554, -14408, -19853, -23357, -24576, -23393, -19922, -14503, -7666, 0, 10120, 19252, 26500, 31157, 32767, 31173, 26531, 19294, 10170, 52, -10072, -19210, -26470, -31142, -32768,-31190, -26562, -19337, -10221, 0, 0, -20, 0, 0, 10120, 19252, 26500, 31157, 32767, 31173, 26531, 19294, 10170, 52, -10072, -19210, -26470, -31142, -32768, -31190, -26562, -19337, -10221, 0, 0, -20, 0, 0, 2047, 4095, 6143, 8191, 6143, 4095, 2047, 0, -2047, -4095, -6143, -8191, -6143, -4095, -2047, 0, 4095, 8191, 12287, 16383, 12287, 8191, 4095, 0, -4095, -8191, -12287, -16383, -12287, -8191, -4095, 0, 6143, 12287, 18431, 24575, 18431, 12287, 6143, 0, -6143, -12287, -18431, -24575, -18431, -12287, -6143, 0, 8191, 16383, 24575, 32767, 24575, 16383, 8191, 0, -8191, -16383, -24575, -32767, -24575, -16383, -8191, 0, 0, -16, 0, 0, 8191, 16383, 24575, 32767, 24575, 16383, 8191, 0, -8191, -16383, -24575,-32767, -24575, -16383, -8191, 0, 0, -16, 0, 0, 12797, 32005, -2563, -4882, 31036, 30160, 2044, -3055, -15627, 26127, 13070, 16362, -16671, -29678, 6177, -20485, 18944, -11289, -2827, -7881, -6189, 21005, 4355,-20769, 19192, 1862, 28916, -28991, -26855, 13586, -2560, 6912, -19223, 15134, -20971, -25400, 26105, -15581, 29176, 11505, -23036, -27908, -14066, -20471, 4325, 2052, -32767, 4858, 4376, -6391, 18424, -27175, -8932, 6921, 3060, 31740, 8447, -27644, 32252, -29963, -18665, 29945, 11004, -8954, -10253, -2819, 1544, -3560, 27103, -17401, 19191,-30229, -17625, 4361, 32751, 13845, -4915, 30241, -26603, 22223, -11258, 13090, -8218, -20726, -17931, -12792, 23813,-16402, -4070, 8424, -24810, -29454, -15641, -11730, -14847, -17968, -32500, 17187, 10461, -26889, 23612, -24610, -20760,-18917, 16115, 5128, -9495, 11275, -20173, -22303, 1498, 2324, 20002, -24, -30735, 8688, -29403, 32252, 7408, 24081, 15848, -14582, -28905, -16, 27149, -29, 4851, 1055, 30732, -15121, 23298, 15618, 754, 5401, -9515,-17143, -28135, -2813, 25309, 14342, 3878, -22277, -7938, -2333, 3586, 528, 17414, -27436, -12022, -22458, 4337, 6860, -16899, 6704, -24341, 24554, -16624, -17425, -8421, -15860, 10976, 16114, -20953, 20481, -1571, 13841, -21222, 2015, 27909, 6669, -18725, 27947, 13831, -1076, 16904, 3873, 14070, -14330, 1539, -553, 30743, 1541, -20725,-27140, 4332, -22770, -21005, 26127, -16910, -8456, -7135, -19993, -787, 23324, -24311, -13070, -2573, -25861, -19433,-27928, 32520, 19450, -30211, 15388, -785, -3365, 18973, 26397, -10497, 26074, -3588, 28170, 2572, 4600, 18946, 23548, -5370, -23059, 12518, -32751, -11724, 2296, 17372, -2551, -22798, -26099, 28678, -2582, -25348, -32482, -21018, -6642, -27145, -19708, -25345, -4118, -2791, -1536, 15094, -14379, 10018, -17608, 17361, 30701, 18696, -12798, -21745, 15851, -9462, 25601, 16377, 30450, -27895, -11761, 29925, 0, 0, -256, 0 }; u16 akao_wave_table_key_nodes[ 16 ] = { 0, 12, 18, 28, 34, 44, 50, 210, 360, 428, 252, 336, 448, 428, 360, 428 }; u8 opcode_size[ 96 ] = { 00, 02, 02, 02, 03, 02, 01, 01, 02, 03, 02, 03, 02, 02, 02, 02, // a0-af 03, 02, 02, 01, 04, 02, 01, 02, 04, 02, 01, 02, 03, 02, 01, 02, // b0-bf 02, 02, 01, 01, 01, 01, 01, 01, 01, 00, 00, 00, 01, 00, 02, 02, // c0-cf 01, 00, 02, 02, 01, 01, 01, 01, 02, 02, 02, 00, 02, 03, 03, 03, // d0-df 00, 00, 00, 00, 00, 00, 00, 00, 03, 04, 03, 04, 03, 01, 00, 00, // e0-ef 00, 00, 02, 01, 03, 01, 02, 03, 02, 01, 00, 00, 00, 03, 03, 00, // f0-ff }; AkaoParser *AKAOPARSER = NULL; AkaoParser::AkaoParser(): m_Music( NULL ) { memset( ( u8* )m_MusicChannelData, 0x00, sizeof( ChannelData ) * 24 ); } AkaoParser::~AkaoParser() { } void AkaoParser::Update() { UpdateDynamicSpuParameters(); if ( m_MusicChannelConfig.active_channel_mask != 0 ) { //V1 = w[80062fea]; u32 tempo = m_MusicChannelConfig.tempo >> 0x10; /* if (V1 != 0) { if (V1 < 80) { tempo += (tempo * V1) >> 0x7; } else { tempo = (tempo * V1) >> 0x8; } } */ m_MusicChannelConfig.tempo_counter += tempo; if ( ( m_MusicChannelConfig.tempo_counter & 0xffff0000 ) /*|| ( w[80062ff8] & 00000004 )*/ ) { m_MusicChannelConfig.tempo_counter &= 0x0000ffff; //[80062f04] = w(0); u32 channel_mask = m_MusicChannelConfig.active_channel_mask; int channel_id = 0; for ( u32 bit = 1; channel_mask != 0; bit <<= 1, channel_id += 1 ) { if ( channel_mask & bit ) { channel_mask ^= bit; m_MusicChannelData[ channel_id ].pause -= 0x0101; if ( ( m_MusicChannelData[ channel_id ].pause & 0x00ff ) == 0 ) { UpdateSequence( m_MusicChannelData, channel_id, m_MusicChannelConfig ); } else if ( ( m_MusicChannelData[ channel_id ].pause & 0xff00 ) == 0 ) { m_MusicChannelData[ channel_id ].pause |= 0x100; m_MusicChannelConfig.unknown_0c &= ~bit; m_MusicChannelConfig.unknown_10 |= bit; } UpdateCounters( m_MusicChannelData, channel_id, m_MusicChannelConfig ); } } if ( m_MusicChannelConfig.tempo_increment_counter != 0 ) { m_MusicChannelConfig.tempo_increment_counter -= 1; m_MusicChannelConfig.tempo += m_MusicChannelConfig.tempo_increment; } if( m_MusicChannelConfig.reverb_depth_increment_counter != 0 ) { m_MusicChannelConfig.reverb_depth_increment_counter -= 1; m_MusicChannelConfig.reverb_depth += m_MusicChannelConfig.tempo_increment_counter; m_MusicChannelConfig.spu_update_flags |= SPU_REVERB; } if( m_MusicChannelConfig.lower_timer_top != 0 ) { m_MusicChannelConfig.lower_timer += 1; if( m_MusicChannelConfig.lower_timer == m_MusicChannelConfig.lower_timer_top ) { m_MusicChannelConfig.lower_timer = 0; m_MusicChannelConfig.upper_timer += 1; if( m_MusicChannelConfig.upper_timer == m_MusicChannelConfig.upper_timer_top ) { m_MusicChannelConfig.upper_timer = 0; m_MusicChannelConfig.top_timer += 1; } } } } } } void AkaoParser::LoadInstruments( const Ogre::String& all_file, const Ogre::String& dat_file ) { // load instruments adpsm { File* file = new File( all_file ); u32 address = file->GetU32LE( 0x0 ) / 8; u32 datasize = file->GetU32LE( 0x4 ); u8* buffer = new u8[ datasize ]; file->GetFileBuffer( buffer, 0x10, datasize ); if ( !SOUNDMAN->PsxWriteDMA( address, buffer, datasize ) ) { LOGGER->Log( "[AkaoParser::LoadVoiceData] error: failed to DMA write sample data.\n" ); } delete[] buffer; delete file; } { File* file = new File( dat_file ); int file_size = file->GetFileSize(); // load index records InstrumentData data; for ( int i = 0; i < file_size; i += 0x40 ) { data.start_offset = file->GetU32LE( i + 0x00 ); data.loop_offset = file->GetU32LE( i + 0x04 ); data.attack_rate = file->GetU8( i + 0x08 ); data.decay_rate = file->GetU8( i + 0x09 ); data.sustain_level = file->GetU8( i + 0x0a ); data.sustain_rate = file->GetU8( i + 0x0b ); data.release_rate = file->GetU8( i + 0x0c ); data.attack_mode = file->GetU8( i + 0x0d ); data.sustain_mode = file->GetU8( i + 0x0e ); data.release_mode = file->GetU8( i + 0x0f ); data.pitch[ 0 ] = file->GetU32LE( i + 0x10 ); data.pitch[ 1 ] = file->GetU32LE( i + 0x14 ); data.pitch[ 2 ] = file->GetU32LE( i + 0x18 ); data.pitch[ 3 ] = file->GetU32LE( i + 0x1c ); data.pitch[ 4 ] = file->GetU32LE( i + 0x20 ); data.pitch[ 5 ] = file->GetU32LE( i + 0x24 ); data.pitch[ 6 ] = file->GetU32LE( i + 0x28 ); data.pitch[ 7 ] = file->GetU32LE( i + 0x2c ); data.pitch[ 8 ] = file->GetU32LE( i + 0x30 ); data.pitch[ 9 ] = file->GetU32LE( i + 0x34 ); data.pitch[ 10 ] = file->GetU32LE( i + 0x38 ); data.pitch[ 11 ] = file->GetU32LE( i + 0x3c ); m_InstrumentData.push_back( data ); } delete file; } } void AkaoParser::UnloadInstruments() { m_InstrumentData.clear(); } void AkaoParser::PlayMusic( const Ogre::String& file ) { if ( m_Music != NULL ) { delete m_Music; } m_Music = new File( file ); if ( m_Music->GetU8( 0 ) == 0x41 && m_Music->GetU8( 1 ) == 0x4b && m_Music->GetU8( 2 ) == 0x41 && m_Music->GetU8( 3 ) == 0x4f) // AKAO { int music_id = m_Music->GetU16LE( 4 ); int length = m_Music->GetU16LE( 6 ); int reverb_mode = m_Music->GetU16LE( 8 ); //A0 = reverb_mode; //func29af0; //[V0 + 0] = w(w[8009a000]); //[V0 + 4] = w(akao_offset + 16); //[V0 + 8] = w(frame_length); //[V0 + c] = w(frame_id); //[V0 + 10] = w(w[8009a008]); /* if (m_MusicChannelConfig.active_channel_mask != 0) { A2 = 80096608; V0 = w[8009a128]; V1 = w[8009a12c]; [8009a12c] = w(0); [8009a128] = w(0); [8009a110] = w(0); m_MusicChannelConfig.for_play_channel_mask = 0; A0 = m_MusicChannelConfig.active_channel_mask | V0 | V1; m_MusicChannelConfig.active_channel_mask = A0; [8009a114] = w(A0 | w[8009a114]); A1 = 1; loop29f18: ; 80029F18 if (A0 XOR A1) { A0 = A0 XOR A1; [A2 + 56] = h(204); [A2 + 0] = w(80049c40); } A1 = A1 << 1; A2 = A2 + 108; 80029F34 bne a0, zero, loop29f18 [$80029f18] } */ //[8009a114] = w(w[8009a114] | 00ffffff); u16 offset_to_akao = 0; m_MusicChannelConfig.active_channel_mask = m_Music->GetU32LE( 0x10 ) & 0x00ffffff; u32 channel_mask = m_MusicChannelConfig.active_channel_mask; int channel_id = 0; for ( u32 bit = 1; channel_mask != 0; bit <<= 1, channel_id += 1 ) { if ( channel_mask & bit ) { channel_mask ^= bit; m_MusicChannelData[ channel_id ].akao_sequence_pointer = 20 + offset_to_akao + 2 + m_Music->GetU16LE( 20 + offset_to_akao ); offset_to_akao += 2; //LOGGER->Log( "Init channel " + ToIntString( channel_id ) + " with offset to AKAO " + ToHexString( m_MusicChannelData[ channel_id ].akao_sequence_pointer, 4, '0' ) + "\n" ); InitChannelInstrument( m_MusicChannelData, channel_id, 0x14 ); //[S3 + 14] = w(80083580); m_MusicChannelData[ channel_id ].volume_multiplier = 0x7f; m_MusicChannelData[ channel_id ].pitch_addition = 0; m_MusicChannelData[ channel_id ].mirror_update_flags = 0; m_MusicChannelData[ channel_id ].volume_level = 0x3fff0000; m_MusicChannelData[ channel_id ].pause = 0x103; m_MusicChannelData[ channel_id ].volume_level_change_ticks = 0; //[S3 + 5e] = h(0); m_MusicChannelData[ channel_id ].volume_index = 0x4000; m_MusicChannelData[ channel_id ].unknown_62 = 0; m_MusicChannelData[ channel_id ].unknown_64 = 0; m_MusicChannelData[ channel_id ].unknown_6c = 0; m_MusicChannelData[ channel_id ].unknown_6e = 0; m_MusicChannelData[ channel_id ].wave1_modifier = 0; //[S3 + 80] = h(0); //[S3 + 90] = h(0); //[S3 + 92] = h(0); //[S3 + 9e] = h(0); //[S3 + a0] = h(0); //[S3 + a4] = h(0); //[S3 + a6] = h(0); m_MusicChannelData[ channel_id ].loop_index = 0; m_MusicChannelData[ channel_id ].saved_pause = 0; m_MusicChannelData[ channel_id ].pause_multiplier = 0; //[S3 + c6] = h(4000); m_MusicChannelData[ channel_id ].pitch_selector = 0; m_MusicChannelData[ channel_id ].pitch_modifier = 0; m_MusicChannelData[ channel_id ].unknown_d2 = 0; //[S3 + da] = h(0); } } m_MusicChannelConfig.for_play_channel_mask = 0; /* [8009a110] = w(0); */ m_MusicChannelConfig.tempo = 0xffff0000; m_MusicChannelConfig.tempo_counter = 1; // this way we update sequence on next update /* [8009a128] = w(0); [8009a12c] = w(0); [8009a130] = w(0); [8009a134] = w(0); [8009a138] = w(0); */ m_MusicChannelConfig.spu_update_flags = 0; m_MusicChannelConfig.reverb_depth = 0; //[8009a148] = w(0); m_MusicChannelConfig.tempo_increment_counter = 0; //[8009a150] = h(0); //[8009a152] = h(0); m_MusicChannelConfig.reverb_depth_increment_counter = 0; //[8009a158] = h(0); m_MusicChannelConfig.upper_timer_top = 0; m_MusicChannelConfig.upper_timer = 0; m_MusicChannelConfig.lower_timer_top = 0; m_MusicChannelConfig.lower_timer = 0; m_MusicChannelConfig.top_timer = 0; /* [8009a15e] = h(0); [8009a160] = h(0); [8009a162] = h(0); if (w[80062ff8] & 1) { [8009a108] = w(0); [8009a118] = w(w[8009a108]); } func2ff4c func30038 func30148 */ } } void AkaoParser::UpdateDynamicSpuParameters() { u32 for_play_channel_mask = 0; if( m_MusicChannelConfig.spu_update_flags & SPU_REVERB ) { s16 reverb_depth = m_MusicChannelConfig.reverb_depth >> 0x10; /* looks like update of total reverb volume if this is ever used V1 = hu[80062fb8]; if (V1 < 80) { reverb_depth = reverb_depth + ((reverb_depth * V1) >> 7); } else { reverb_depth = (reverb_depth * V1) >> 8; } */ u8 pan = 0x40 /*hu[80062f70]*/; s16 left = reverb_depth; s16 right = reverb_depth; if( pan < 0x40 ) { right = reverb_depth - ( ( reverb_depth * ( pan ^ 0x3f ) ) >> 6 ); } else { left = reverb_depth - ( ( reverb_depth * ( pan & 0x3f ) ) >> 6 ); } SOUNDMAN->PsxSetReverbDepth( left, right ); m_MusicChannelConfig.spu_update_flags ^= SPU_REVERB; } if ( m_MusicChannelConfig.active_channel_mask != 0 ) { for_play_channel_mask |= m_MusicChannelConfig.for_play_channel_mask; u32 channel_mask = m_MusicChannelConfig.active_channel_mask; int channel_id = 0; for ( u32 bit = 1; channel_mask != 0; bit <<= 1, channel_id += 1 ) { if ( channel_mask & bit ) { channel_mask ^= bit; UpdatePitchAndVolume( m_MusicChannelData, channel_id ); if ( m_MusicChannelData[ channel_id ].spu_update_flags ) { UpdateSpu( m_MusicChannelData, channel_id ); } } } m_MusicChannelConfig.for_play_channel_mask = 0; } if ( for_play_channel_mask != 0 ) { UpdatePlayChannel( true, for_play_channel_mask ); } } void AkaoParser::UpdatePitchAndVolume( ChannelData* channel_data, int channel_id ) { int temp = ( ( channel_data[ channel_id ].volume_level >> 16) * channel_data[ channel_id ].volume_multiplier ) >> 7; if ( channel_data[ channel_id ].spu_update_flags & ( SPU_LEFT_VOLUME | SPU_RIGHT_VOLUME ) ) { //temp = ( ( temp + h[T0 + d8] ) * ( hu[80062f5e] & 0x7f ) ) >> 7; temp = ( temp * 0x7f ) >> 7; /* if (hu[8009c5a8] != 0) { temp = (temp * h[8009c5a2 + channel_id * c]) >> 7; } */ int volume_index = ( /*h[T0 + da] + */channel_data[ channel_id ].volume_index >> 8) & 0xff; /* V1 = w[8009a104]; if (V1 == 1) // stereo */ { channel_data[ channel_id ].left_volume = ( temp * akao_left_volume_table[ volume_index ] ) >> 0xf; channel_data[ channel_id ].right_volume = ( temp * akao_right_volume_table[ volume_index ] ) >> 0xf; } /* else if (V1 == 4) { channel_data[ channel_id ].left_volume = (temp * akao_left_volume_table[ volume_index ] ) >> 0xf; channel_data[ channel_id ].right_volume = (temp * akao_right_volume_table[ volume_index ] ) >> 0xf; if (A1 & 00aaaaaa == 0) { channel_data[ channel_id ].left_volume = 0 NOR channel_data[ channel_id ].left_volume; } else { channel_data[ channel_id ].right_volume = 0 NOR channel_data[ channel_id ].right_volume; } } else { channel_data[ channel_id ].left_volume = ( temp * h[80049cc4]) >> 0xf; channel_data[ channel_id ].right_volume = ( temp * h[80049cc4]) >> 0xf; } */ } u16 new_pitch = 0; /* if (w[T0 + 38] & 00000010) { V1 = h[T0 + d6] + h[T0 + 36] + w[T0 - 10]; // uses pitch from previous channel } else*/ if ( channel_data[ channel_id ].spu_update_flags & SPU_PITCH ) { new_pitch = channel_data[ channel_id ].pitch_base + ( channel_data[ channel_id ].pitch_addition >> 0x10 ) + channel_data[ channel_id ].pitch_addition2; } if (/*(w[T0 + 38] & 00000010) ||*/ ( channel_data[ channel_id ].spu_update_flags & SPU_PITCH ) ) { channel_data[ channel_id ].spu_update_flags |= SPU_PITCH; channel_data[ channel_id ].pitch = new_pitch & 0x3fff; } } void AkaoParser::UpdateSpu( ChannelData* channel_data, int channel_id ) { //S1 = A0; //S0 = A1; if ( channel_data[ channel_id ].spu_update_flags & SPU_PITCH ) { /* A0 = S1; A1 = hu[S0 + 1c]; // f8 func395c8; */ //LOGGER->Log( "UpdateSpu::SPU_PITCH channel " + Ogre::StringConverter::toString( channel_id ) + " value:" + Ogre::StringConverter::toString( channel_data[ channel_id ].pitch ) + ".\n" ); SOUNDMAN->SetVoicePitch( channel_id, channel_data[ channel_id ].pitch ); channel_data[ channel_id ].spu_update_flags &= ~SPU_PITCH; } if ( channel_data[ channel_id ].spu_update_flags & ( SPU_LEFT_VOLUME | SPU_RIGHT_VOLUME ) ) { /* A0 = S1; A1 = h[S0 + 28]; // 104 A2 = h[S0 + 2a]; // 106 func393c8; */ //LOGGER->Log( "UpdateSpu::SPU_LEFT_VOLUME|SPU_RIGHT_VOLUME channel " + Ogre::StringConverter::toString( channel_id ) + " value:" + Ogre::StringConverter::toString( channel_data[ channel_id ].left_volume ) + " " + Ogre::StringConverter::toString( channel_data[ channel_id ].right_volume ) + ".\n" ); SOUNDMAN->SetVoiceVolume( channel_id, channel_data[ channel_id ].left_volume, channel_data[ channel_id ].right_volume ); channel_data[ channel_id ].spu_update_flags &= ~( SPU_LEFT_VOLUME | SPU_RIGHT_VOLUME ); } if ( channel_data[ channel_id ].spu_update_flags & SPU_START_OFFSET ) { /* A0 = S1; A1 = w[S0 + 8]; func39644; // we set start address here */ //LOGGER->Log( "UpdateSpu::SPU_START_OFFSET channel " + Ogre::StringConverter::toString( channel_id ) + " value:" + Ogre::StringConverter::toString( channel_data[ channel_id ].start_offset ) + ".\n" ); SOUNDMAN->SetVoiceStartAddress( channel_id, channel_data[ channel_id ].start_offset ); channel_data[ channel_id ].spu_update_flags &= ~SPU_START_OFFSET; } if ( channel_data[ channel_id ].spu_update_flags & SPU_LOOP_OFFSET ) { /* A0 = S1; A1 = w[S0 + c]; func396c0; */ //LOGGER->Log( "UpdateSpu::SPU_LOOP_OFFSET channel " + Ogre::StringConverter::toString( channel_id ) + " value:" + Ogre::StringConverter::toString( channel_data[ channel_id ].loop_offset ) + ".\n" ); SOUNDMAN->SetVoiceLoopAddress( channel_id, channel_data[ channel_id ].loop_offset ); channel_data[ channel_id ].spu_update_flags &= ~SPU_LOOP_OFFSET; } if ( channel_data[ channel_id ].spu_update_flags & ( SPU_SUSTAIN_RATE | SPU_SUSTAIN_MODE ) ) { /* A0 = S1; A1 = h[S0 + 24]; // 100 A2 = h[S0 + 14]; // f0 func398ec; */ //LOGGER->Log( "UpdateSpu::SPU_SUSTAIN_RATE|SPU_SUSTAIN_MODE channel " + Ogre::StringConverter::toString( channel_id ) + " value:" + Ogre::StringConverter::toString( channel_data[ channel_id ].sustain_rate ) + " " + Ogre::StringConverter::toString( channel_data[ channel_id ].sustain_mode ) + ".\n" ); SOUNDMAN->SetVoiceSustainRate( channel_id, channel_data[ channel_id ].sustain_rate, (SoundManager::SpuRateMode)channel_data[ channel_id ].sustain_mode ); channel_data[ channel_id ].spu_update_flags &= ~( SPU_SUSTAIN_RATE | SPU_SUSTAIN_MODE ); } if ( channel_data[ channel_id ].spu_update_flags & ( SPU_ATTACK_RATE | SPU_ATTACK_MODE ) ) { /* A0 = S1; A1 = h[S0 + 1e]; // fa A2 = h[S0 + 10]; // ec func39850; */ //LOGGER->Log( "UpdateSpu::SPU_ATTACK_RATE|SPU_ATTACK_MODE channel " + Ogre::StringConverter::toString( channel_id ) + " value:" + Ogre::StringConverter::toString( channel_data[ channel_id ].attack_rate ) + " " + Ogre::StringConverter::toString( channel_data[ channel_id ].attack_mode ) + ".\n" ); SOUNDMAN->SetVoiceAttackRate( channel_id, channel_data[ channel_id ].attack_rate, ( SoundManager::SpuRateMode )channel_data[ channel_id ].attack_mode ); channel_data[ channel_id ].spu_update_flags &= ~( SPU_ATTACK_RATE | SPU_ATTACK_MODE ); } if ( channel_data[ channel_id ].spu_update_flags & ( SPU_RELEASE_RATE | SPU_RELEASE_MODE ) ) { /* A0 = S1; A1 = h[S0 + 26]; // 102 // release rate A2 = h[S0 + 18]; // f4 // release mode func399d0; */ //LOGGER->Log( "UpdateSpu::SPU_RELEASE_RATE|SPU_RELEASE_MODE channel " + Ogre::StringConverter::toString( channel_id ) + " value:" + Ogre::StringConverter::toString( channel_data[ channel_id ].release_rate ) + " " + Ogre::StringConverter::toString( channel_data[ channel_id ].release_mode ) + ".\n" ); SOUNDMAN->SetVoiceReleaseRate( channel_id, channel_data[ channel_id ].release_rate, (SoundManager::SpuRateMode)channel_data[ channel_id ].release_mode ); channel_data[ channel_id ].spu_update_flags &= ~( SPU_RELEASE_RATE | SPU_RELEASE_MODE ); } if ( channel_data[ channel_id ].spu_update_flags & ( SPU_DECAY_RATE | SPU_SUSTAIN_LEVEL ) ) { /* A0 = S1; A1 = h[S0 + 20]; // fc // decay rate. func3973c; A0 = S1; A1 = h[S0 + 22]; // fe // sustain level. func397c8; */ //LOGGER->Log( "UpdateSpu::SPU_DECAY_RATE|SPU_SUSTAIN_LEVEL channel " + Ogre::StringConverter::toString( channel_id ) + " value:" + Ogre::StringConverter::toString( channel_data[ channel_id ].decay_rate ) + " " + Ogre::StringConverter::toString( channel_data[ channel_id ].sustain_level ) + ".\n" ); SOUNDMAN->SetVoiceDecayRate( channel_id, channel_data[ channel_id ].decay_rate ); SOUNDMAN->SetVoiceSustainLevel( channel_id, channel_data[ channel_id ].sustain_level ); channel_data[ channel_id ].spu_update_flags &= ~( SPU_DECAY_RATE | SPU_SUSTAIN_LEVEL ); } } void AkaoParser::UpdatePlayChannel( bool on, u32 channel_mask ) { int channel_id = 0; for ( u32 bit = 1; channel_mask != 0; bit <<= 1, channel_id += 1 ) { if ( channel_mask & bit ) { channel_mask ^= bit; if ( on == true ) { SOUNDMAN->PsxChannelPlay( channel_id ); std::cout << "Play channel " << channel_id << std::endl; } else { SOUNDMAN->PsxChannelStop( channel_id ); std::cout << "Stop channel " << channel_id << std::endl; } } } } void AkaoParser::UpdateSequence( ChannelData* channel_data, int channel_id, ChannelConfig& channel_config ) { //LOGGER->Log( "UpdateSequence for channel " + ToIntString( channel_id ) + "\n" ); u8 opcode; for( ;; ) { opcode = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer ); if( opcode < 0xa0 ) { channel_data[ channel_id ].akao_sequence_pointer += 1; break; } else if( opcode == 0xa1 ) // load instrument { LOGGER->Log( " 0xA1 [NOT COMPLETE] " ); int instrument_id = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ); //LOGGER->Log( "Load instrument " + ToIntString( instrument_id ) + "with 0xA1.\n" ); /* A0 = hu[A3 + 24]; if (w[80062f04] != 0) { A0 = A0 - 18; } if (w[A3 + 38] & 00000100) { [A1 + 24] = w(w[A1 + 24] & (0 NOR (1 << A0))) [A3 + 38] = w(w[A3 + 38] & fffffeff) } if (hu[A3 + 54] != 0 || (A2 & w[A1 + c] & w[80099fcc]) == 0) { [A3 + e0] = w(w[A3 + e0] | 00000010); [A3 + 30] = w((w[A3 + 30] * w[80075f28 + instrument_id * 40 + 10]) / w[80075f28 + hu[A3 + 58] * 40 + 10]); } */ // if loaded adsr release rate, load rest // note from G /* if (w[A3 + 38] & 00000200) { InstrumentData data = m_InstrumentData[ instrument_id ]; channel_data[ channel_id ].instrument_id = instrument_id; channel_data[ channel_id ].start_offset = data.start_offset; channel_data[ channel_id ].loop_offset = data.loop_offset; channel_data[ channel_id ].attack_rate = data.attack_rate; channel_data[ channel_id ].decay_rate = data.decay_rate; channel_data[ channel_id ].attack_mode = data.attack_mode; channel_data[ channel_id ].sustain_mode = data.sustain_mode; channel_data[ channel_id ].sustain_level = data.sustain_level; channel_data[ channel_id ].sustain_rate = data.sustain_rate; channel_data[ channel_id ].spu_update_flags |= SPU_START_OFFSET | SPU_ATTACK_RATE | SPU_SUSTAIN_RATE | SPU_ATTACK_MODE | SPU_DECAY_RATE | SPU_SUSTAIN_MODE | SPU_SUSTAIN_LEVEL | SPU_LOOP_OFFSET; // update everything we just set } else // init all data */ { InitChannelInstrument( channel_data, channel_id, instrument_id ); } channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xa2 ) // pause { LOGGER->Log( " 0xA2 " ); u8 value = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ); channel_data[ channel_id ].pause_multiplier = 0; channel_data[ channel_id ].saved_pause = value; channel_data[ channel_id ].pause = ( value << 8 ) | value; //LOGGER->Log( "Set pause to 0x" + ToHexString( value, 2, '0' ) + ".\n" ); channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xa3 ) // set volume multiplier { LOGGER->Log( " 0xA3 " ); channel_data[ channel_id ].volume_multiplier = ( s8 )( m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ) ); channel_data[ channel_id ].spu_update_flags |= SPU_LEFT_VOLUME | SPU_RIGHT_VOLUME; //LOGGER->Log( "Set volume multiplier to 0x" + ToHexString( channel_data[ channel_id ].volume_multiplier, 2, '0' ) + ".\n" ); channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xa5 ) // set pitch correction { LOGGER->Log( " 0xA5 " ); channel_data[ channel_id ].pitch_correction = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ); //LOGGER->Log( "Set pitch correction to 0x" + ToHexString( channel_data[ channel_id ].pitch_correction, 4, '0' ) + ".\n" ); channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xa6 ) // increment pitch correction { LOGGER->Log( " 0xA6 Increment pitch correction.\n" ); channel_data[ channel_id ].pitch_correction = ( channel_data[ channel_id ].pitch_correction + 1 ) & 0xf; channel_data[ channel_id ].akao_sequence_pointer += 1; } else if( opcode == 0xa7 ) // decrement pitch correction { LOGGER->Log( " 0xA7 Decrement pitch correction.\n" ); channel_data[ channel_id ].pitch_correction = ( channel_data[ channel_id ].pitch_correction - 1 ) & 0xf; channel_data[ channel_id ].akao_sequence_pointer += 1; } else if( opcode == 0xa8 ) // set volume { LOGGER->Log( " 0xA8 " ); channel_data[ channel_id ].volume_multiplier = ( s8 )( m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ) ); channel_data[ channel_id ].spu_update_flags |= SPU_LEFT_VOLUME | SPU_RIGHT_VOLUME; channel_data[ channel_id ].volume_level_change_ticks = 0; channel_data[ channel_id ].volume_level = ( s8 )( m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ) ) << 0x17; //LOGGER->Log( "Set volume to 0x" + ToHexString(channel_data[ channel_id ].volume_level, 8, '0' ) + " and reset volume_level_change_ticks.\n" ); channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xa9 ) // set volume increase/descrease { LOGGER->Log( " 0xA9 " ); u16 value1 = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ); s8 value2 = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 2 ); value1 = ( value1 == 0 ) ? 0x100 : value1; channel_data[ channel_id ].volume_level_change_ticks = value1; channel_data[ channel_id ].volume_level &= 0xffff0000; channel_data[ channel_id ].volume_level_add = ( ( value2 << 0x17 ) - channel_data[ channel_id ].volume_level ) / channel_data[ channel_id ].volume_level_change_ticks; //LOGGER->Log( "Set volume tick to 0x" + ToHexString( channel_data[ channel_id ].volume_level_change_ticks, 4, '0' ) + " and " ); //LOGGER->Log( "volume_level_add 0x" + ToHexString( channel_data[ channel_id ].volume_level_add, 8, '0' ) + ".\n" ); channel_data[ channel_id ].akao_sequence_pointer += 3; } else if( opcode == 0xaa ) // set volume pan { LOGGER->Log( " 0xAA " ); channel_data[ channel_id ].spu_update_flags |= SPU_LEFT_VOLUME | SPU_RIGHT_VOLUME; channel_data[ channel_id ].volume_index = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ) << 0x8; channel_data[ channel_id ].unknown_62 = 0; //LOGGER->Log( "Set volume pan to 0x" + ToHexString( channel_data[ channel_id ].volume_index, 4, '0' ) + ".\n" ); channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xad ) // ??? { LOGGER->Log( " 0xAD [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xb1 ) // ??? { LOGGER->Log( " 0xB1 [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xb4 ) // set wave 1 { LOGGER->Log( " 0xB4 " ); channel_data[ channel_id ].mirror_update_flags &= 0x00000001; u16 value1 = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ); u16 value2 = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 2 ); u16 value3 = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 3 ); if( channel_data[ channel_id ].unknown_54 != 0 ) { channel_data[ channel_id ].wave1_delay = 0; if( value1 != 0 ) { channel_data[ channel_id ].wave1_modifier = value1 << 0x8; } } else { channel_data[ channel_id ].wave1_delay = value1; } if( value2 == 0 ) { value2 = 0x100; } channel_data[ channel_id ].wave1_refresh_interval = value2; channel_data[ channel_id ].wave1_table_node_index = value3; u16 pitch_base = channel_data[ channel_id ].pitch_base; if( ( channel_data[ channel_id ].wave1_modifier & 0x8000 ) == 0 ) { pitch_base = ( pitch_base * 0xf ) >> 8; } channel_data[ channel_id ].wave1_multiplier = ( ( ( channel_data[ channel_id ].wave1_modifier & 0x7f00 ) >> 8 ) * pitch_base ) >> 7; channel_data[ channel_id ].wave1_delay_current = channel_data[ channel_id ].wave1_delay; channel_data[ channel_id ].wave1_refresh_interval_counter = channel_data[ channel_id ].wave1_table_node_index; channel_data[ channel_id ].wave1_table_index = akao_wave_table_key_nodes[ channel_data[ channel_id ].wave1_table_node_index ]; //LOGGER->Log( "Set wave1 refresh interval to 0x" + ToHexString( channel_data[ channel_id ].wave1_refresh_interval, 4, '0' ) + " " ); //LOGGER->Log( ", wave1 node index to 0x" + ToHexString( channel_data[ channel_id ].wave1_table_node_index, 4, '0' ) + " " ); //LOGGER->Log( "and wave1 delay (or wave1 modifier) to 0x" + ToHexString( value1, 2, '0' ) + ".\n" ); channel_data[ channel_id ].akao_sequence_pointer += 4; } else if( opcode == 0xb5 ) // set wave modifier { LOGGER->Log( " 0xB5 " ); channel_data[ channel_id ].wave1_modifier = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ) << 0x8; u16 pitch_base = channel_data[ channel_id ].pitch_base; if( ( channel_data[ channel_id ].wave1_modifier & 0x8000 ) == 0 ) { pitch_base = ( pitch_base * 0xf ) >> 8; } channel_data[ channel_id ].wave1_multiplier = ( ( ( channel_data[ channel_id ].wave1_modifier & 0x7f00) >> 8 ) * pitch_base ) >> 7; //LOGGER->Log( "Set wave modifier to 0x" + ToHexString( channel_data[ channel_id ].wave1_modifier, 4, '0' ) + ".\n" ); channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xc2 ) // turn reverb on { LOGGER->Log( " 0xC2 [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 1; } else if( opcode == 0xc8 ) // set loop point { LOGGER->Log( " 0xC8 " ); channel_data[ channel_id ].loop_index = ( channel_data[ channel_id ].loop_index + 1 ) & 3; u16 index = channel_data[ channel_id ].loop_index; channel_data[ channel_id ].loop_pointer[ index ] = channel_data[ channel_id ].akao_sequence_pointer + 1; channel_data[ channel_id ].loop_count[ index ] = 0; //LOGGER->Log( "Set loop index 0x" + ToHexString( index, 4, '0' ) + ".\n" ); channel_data[ channel_id ].akao_sequence_pointer += 1; } else if( opcode == 0xc9 ) // conditional jump { LOGGER->Log( " 0xC9 " ); u16 value = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ); value = ( value == 0 ) ? 0x100 : value; u16 index = channel_data[ channel_id ].loop_index; channel_data[ channel_id ].loop_count[ index ] += 1; if( channel_data[ channel_id ].loop_count[ index ] != value ) { channel_data[ channel_id ].akao_sequence_pointer = channel_data[ channel_id ].loop_pointer[ index ]; //LOGGER->Log( "Repeat conditional jump with index 0x" + ToHexString( index, 4, '0' ) + " and value 0x" + ToHexString( value, 4, '0' ) + ". Current loop count 0x" + ToHexString( channel_data[ channel_id ].loop_count[ index ], 4, '0' ) + "\n" ); } else { channel_data[ channel_id ].loop_index = ( index - 1 ) & 3; //LOGGER->Log( "Go through conditional jump with index 0x" + ToHexString( index, 4, '0' ) + " and value 0x" + ToHexString( value, 4, '0' ) + ".\n" ); } channel_data[ channel_id ].akao_sequence_pointer += 1; } else if( opcode == 0xcc ) { LOGGER->Log( " 0xCC Set unknown_6e to 1.\n" ); channel_data[ channel_id ].unknown_6e = 1; channel_data[ channel_id ].akao_sequence_pointer += 1; } else if( opcode == 0xcd ) // does nothing { LOGGER->Log( " 0xCD Do nothing.\n" ); channel_data[ channel_id ].akao_sequence_pointer += 1; } else if( opcode == 0xd9 ) { LOGGER->Log( " 0xD9 [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xe0 ) // ??? { LOGGER->Log( " 0xE0 [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 1; } else if( opcode == 0xe2 ) // ??? { LOGGER->Log( " 0xE2 [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 1; } else if( opcode == 0xe8 ) // set tempo { LOGGER->Log( " 0xE8 " ); channel_config.tempo = m_Music->GetU16LE( channel_data[ channel_id ].akao_sequence_pointer + 1 ) << 0x10; channel_config.tempo_increment_counter = 0; //LOGGER->Log( "Set tempo to 0x" + ToHexString( channel_config.tempo, 8, '0' ) + " and reset tempo increment counter to 0.\n" ); channel_data[ channel_id ].akao_sequence_pointer += 3; } else if( opcode == 0xea ) // set reverb depth { LOGGER->Log( " 0xEA " ); channel_config.spu_update_flags |= SPU_REVERB; channel_config.reverb_depth = m_Music->GetU16LE( channel_data[ channel_id ].akao_sequence_pointer + 1 ) << 0x10; channel_config.reverb_depth_increment_counter = 0; //LOGGER->Log( "Set reverb depth to 0x" + ToHexString( channel_config.reverb_depth, 8, '0' ) + " and reset reverb depth increment counter to 0.\n" ); channel_data[ channel_id ].akao_sequence_pointer += 3; } else if( opcode == 0xec ) { LOGGER->Log( " 0xEC [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 3; } else if( opcode == 0xee ) // ??? { LOGGER->Log( " 0xEE [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 3; } else if( opcode == 0xf0 ) { LOGGER->Log( " 0xF0 [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 4; } else if( opcode == 0xf1 ) { LOGGER->Log( " 0xF1 [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 4; } else if( opcode == 0xf2 ) // load instrument { LOGGER->Log( " 0xF2 " ); int instrument_id = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ); //LOGGER->Log( "Load instrument " + ToIntString( instrument_id ) + " with 0xF2.\n" ); InstrumentData data = m_InstrumentData[ instrument_id ]; if( ( channel_data[ channel_id ].unknown_54 != 0 ) /*|| ( (A2 & w[A1 + c] & w[80099fcc]) == 0 )*/ ) { channel_data[ channel_id ].spu_update_flags |= SPU_PITCH; channel_data[ channel_id ].pitch_base = ( channel_data[ channel_id ].pitch_base * data.pitch[ 0 ] ) / m_InstrumentData[ channel_data[ channel_id ].instrument_id ].pitch[ 0 ]; } channel_data[ channel_id ].instrument_id = instrument_id; channel_data[ channel_id ].start_offset = 0x00076fe0; channel_data[ channel_id ].loop_offset = data.loop_offset; channel_data[ channel_id ].attack_rate = data.attack_rate; channel_data[ channel_id ].decay_rate = data.decay_rate; channel_data[ channel_id ].sustain_level = data.sustain_level; channel_data[ channel_id ].sustain_rate = data.sustain_rate; channel_data[ channel_id ].attack_mode = data.attack_mode; channel_data[ channel_id ].sustain_mode = data.sustain_mode; channel_data[ channel_id ].spu_update_flags |= SPU_START_OFFSET | SPU_ATTACK_RATE | SPU_SUSTAIN_RATE | SPU_ATTACK_MODE | SPU_DECAY_RATE | SPU_SUSTAIN_MODE | SPU_SUSTAIN_LEVEL | SPU_LOOP_OFFSET; if( ( channel_data[ channel_id ].mirror_update_flags & 0x00000200 ) == 0 ) { channel_data[ channel_id ].release_rate = data.release_rate; channel_data[ channel_id ].release_mode = data.release_mode; channel_data[ channel_id ].spu_update_flags |= SPU_RELEASE_RATE | SPU_RELEASE_MODE; } channel_data[ channel_id ].akao_sequence_pointer += 2; } else if( opcode == 0xfd ) // reset timers lower and upper { LOGGER->Log( " 0xFD Reset upper timer to 0 with bound " ); channel_config.upper_timer_top = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 2 ); //LOGGER->Log( ToHexString( channel_config.upper_timer_top, 4, '0' ) + " and lower timer to 0 with bound " ); channel_config.upper_timer = 0; channel_config.lower_timer_top = m_Music->GetU8( channel_data[ channel_id ].akao_sequence_pointer + 1 ); //LOGGER->Log( ToHexString( channel_config.lower_timer_top, 4, '0' ) + ".\n" ); channel_config.lower_timer = 0; channel_data[ channel_id ].akao_sequence_pointer += 3; } else if( opcode == 0xfe ) // reset timer top { LOGGER->Log( " 0xFE Reset top timer to " ); channel_config.top_timer = m_Music->GetU16LE( channel_data[ channel_id ].akao_sequence_pointer + 1 ); //LOGGER->Log( ToHexString( channel_config.top_timer, 4, '0' ) + ".\n" ); channel_data[ channel_id ].akao_sequence_pointer += 3; } else if( opcode == 0xff ) { LOGGER->Log( " 0xFF [UNIMPLEMENTED]\n" ); channel_data[ channel_id ].akao_sequence_pointer += 4; } else { //LOGGER->Log( ToHexString( opcode, 2, '0' ) + " [UNKNOWN]\n" ); break; } } if( opcode != 0xa0 ) { //LOGGER->Log( " 0x" + ToHexString( opcode, 2, '0' ) + " PLAY.\n" ); u8 ret_op = NextSequenceHandle( channel_data, channel_id, channel_config ); if( channel_data[ channel_id ].pause_multiplier != 0) { channel_data[ channel_id ].pause = channel_data[ channel_id ].pause_multiplier * 0x101; } if( ( channel_data[ channel_id ].pause & 0xff ) == 0 ) { channel_data[ channel_id ].pause = akao_pause_table[ opcode % 11 ]; } if( ( ( ret_op - 0x84 ) >= 0xb ) && ( ( channel_data[ channel_id ].unknown_6e & 5 ) == 0 ) ) { channel_data[ channel_id ].pause -= 0x0200; } channel_data[ channel_id ].saved_pause = channel_data[ channel_id ].pause & 0x00ff; if( opcode >= 0x8f ) { channel_data[ channel_id ].unknown_6c = 0; channel_data[ channel_id ].unknown_6e &= 0xfffd; channel_data[ channel_id ].pitch_addition2 = 0; channel_data[ channel_id ].unknown_d8 = 0; } else if( opcode < 0x84 ) { u32 pitch_base = 0; if( channel_data[ channel_id ].mirror_update_flags & 0x00000008 ) { /* S2 = opcode / b; if (hu[channel_data + 54] == 0) { [channels_config + 8] = w(w[channels_config + 8] | mask); } else { [80099fd0] = w(w[80099fd0] | mask); } V1 = (S2 & ff) / c; A0 = (S2 & ff) % c A2 = w[channel_data + 14]; A0 = A0 & ff; V0 = A0 * 5; A2 = A2 + V0; if (bu[A2] != hu[channel_data + 58]) { [channel_data + 58] = h(bu[A2]); V0 = bu[A2] * 40; [channel_data + e4] = w(w[80075f28 + V0]); [channel_data + e8] = w(w[80075f2c + V0]); [channel_data + fa] = h(bu[80075f30 + V0]); [channel_data + fc] = h(bu[80075f31 + V0]); [channel_data + fe] = h(bu[80075f32 + V0]); [channel_data + 100] = h(bu[80075f33 + V0]); [channel_data + ec] = w(bu[80075f35 + V0]); [channel_data + f0] = w(bu[80075f36 + V0]); if ((w[channel_data + 38] & 200) == 0) { V0 = bu[A2] * 40; [channel_data + 102] = h(bu[80075f34 + V0]); [channel_data + f4] = w(bu[80075f37 + V0]); [channel_data + e0] = w(w[channel_data + e0] | 1ff80); } else { [channel_data + e0] = w(w[channel_data + e0] | 1bb80); } } V1 = bu[A2 + 1]; A1 = (S2 & ff) / c; V1 = (S2 & ff) % c; A1 = A1 & ff; A0 = w[80075f38 + bu[A2 + 0] * 40 + V1 * 4]; if (A1 >= 7) { V0 = A1 - 6; A0 = V0 << A0; } else if (A1 < 6) { V0 = 6 - A1; A0 = A0 >> V0; } [channel_data + 44] = w((bu[A2 + 2] + (bu[A2 + 3] << 8)) << 10); [channel_data + 60] = h(bu[A2 + 4] << 8); */ } else { u8 pitch_index = opcode / 11 + channel_data[ channel_id ].pitch_correction * 12; if( ( channel_data[ channel_id ].unknown_6c != 0 ) && ( channel_data[ channel_id ].unknown_6a != 0 ) ) { channel_data[ channel_id ].unknown_68 = channel_data[ channel_id ].unknown_6c; channel_data[ channel_id ].unknown_d2 = pitch_index + channel_data[ channel_id ].pitch_selector - channel_data[ channel_id ].unknown_6a - channel_data[ channel_id ].unknown_d4; channel_data[ channel_id ].saved_pitch = channel_data[ channel_id ].unknown_6a - channel_data[ channel_id ].pitch_selector - channel_data[ channel_id ].unknown_d4; pitch_index = channel_data[ channel_id ].unknown_6a + channel_data[ channel_id ].unknown_d4; } else { channel_data[ channel_id ].saved_pitch = pitch_index; pitch_index += channel_data[ channel_id ].pitch_selector; } if( ( channel_data[ channel_id ].unknown_6e & 0x0002 ) == 0 ) { if( channel_data[ channel_id ].unknown_54 == 0 ) { channel_config.for_play_channel_mask |= ( 1 << channel_id ); if( channel_data[ channel_id ].mirror_update_flags & 0x00000100 ) { u16 mirror_channel_id = channel_data[ channel_id ].mirror_channel_id; if( mirror_channel_id >= 0x18 ) { mirror_channel_id -= 0x18; } channel_config.for_play_channel_mask |= ( 1 << mirror_channel_id ); } } /* else { [80099fd0] = w(w[80099fd0] | ( 1 << channel_id )); } */ channel_data[ channel_id ].unknown_64 = 0; } u8 mod = pitch_index / 12; pitch_base = m_InstrumentData[ channel_data[ channel_id ].instrument_id ].pitch[ pitch_index % 12 ]; if( mod >= 7 ) { pitch_base <<= ( mod - 6 ); } else if( mod < 6 ) { pitch_base >>= ( 6 - mod ); } } if( channel_data[ channel_id ].unknown_54 == 0 ) { channel_config.unknown_0c |= ( 1 << channel_id ); } /* else { [80099fd4] = w(w[80099fd4] | ( 1 << channel_id )); } */ channel_data[ channel_id ].spu_update_flags |= SPU_LEFT_VOLUME | SPU_RIGHT_VOLUME | SPU_PITCH; s16 pitch_modifier = channel_data[ channel_id ].pitch_modifier; if( pitch_modifier != 0 ) { if( pitch_modifier > 0 ) { pitch_modifier = ( pitch_base * pitch_modifier ) >> 7; } else { pitch_modifier = ( pitch_base * pitch_modifier ) >> 8; } pitch_base = ( pitch_base + pitch_modifier ) & 0xffff; } channel_data[ channel_id ].pitch_base = pitch_base; if( channel_data[ channel_id ].mirror_update_flags & 0x00000001 ) { u16 wave1_modifier = ( channel_data[ channel_id ].wave1_modifier & 0x7f00 ) >> 8; if( channel_data[ channel_id ].wave1_modifier & 0x8000 ) { pitch_base = wave1_modifier * pitch_base; } else { pitch_base = wave1_modifier * ( ( pitch_base * 0xf ) >> 8 ); } channel_data[ channel_id ].wave1_multiplier = pitch_base >> 0x7; channel_data[ channel_id ].wave1_delay_current = channel_data[ channel_id ].wave1_delay; channel_data[ channel_id ].wave1_refresh_interval_counter = 1; channel_data[ channel_id ].wave1_table_index = akao_wave_table_key_nodes[ channel_data[ channel_id ].wave1_table_node_index ]; } if( channel_data[ channel_id ].mirror_update_flags & 0X00000002 ) { channel_data[ channel_id ].wave2_delay_current = channel_data[ channel_id ].wave2_delay; channel_data[ channel_id ].wave2_refresh_interval_counter = 1; channel_data[ channel_id ].wave2_table_index = akao_wave_table_key_nodes[ channel_data[ channel_id ].wave2_table_node_index ]; } if( channel_data[ channel_id ].mirror_update_flags & 0x00000004 ) { channel_data[ channel_id ].wave3_refresh_interval_counter = 1; channel_data[ channel_id ].wave3_table_index = akao_wave_table_key_nodes[ channel_data[ channel_id ].wave3_table_node_index ]; } channel_data[ channel_id ].pitch_addition2 = 0; channel_data[ channel_id ].unknown_d8 = 0; channel_data[ channel_id ].pitch_addition = 0; } u16 unknown_d2 = channel_data[ channel_id ].unknown_d2; channel_data[ channel_id ].unknown_6e = ( channel_data[ channel_id ].unknown_6e & 0xfffd ) | ( ( channel_data[ channel_id ].unknown_6e & 0x0001 ) << 1 ); if( unknown_d2 != 0 ) { channel_data[ channel_id ].saved_pitch += unknown_d2; u8 selected_pitch = channel_data[ channel_id ].saved_pitch + channel_data[ channel_id ].pitch_selector; u32 pitch_value = 0; if( channel_data[ channel_id ].unknown_54 == 0 ) { pitch_value = m_InstrumentData[ channel_data[ channel_id ].instrument_id ].pitch[ selected_pitch % 12 ]; s16 pitch_modifier = channel_data[ channel_id ].pitch_modifier; if( pitch_modifier != 0 ) { if( pitch_modifier > 0 ) { pitch_modifier = ( pitch_value * pitch_modifier ) >> 7; } else { pitch_modifier = ( pitch_value * pitch_modifier ) >> 8; } pitch_value += pitch_modifier; } } else { pitch_value = m_InstrumentData[ channel_data[ channel_id ].instrument_id ].pitch[ selected_pitch %= 12 ]; } pitch_value <<= 0x10; selected_pitch /= 12; if( selected_pitch >= 7 ) { pitch_value <<= ( selected_pitch - 6 ); } else if (selected_pitch < 6) { pitch_value >>= ( 6 - selected_pitch ); } channel_data[ channel_id ].unknown_64 = channel_data[ channel_id ].unknown_68; channel_data[ channel_id ].unknown_d2 = 0; channel_data[ channel_id ].pitch_growth = (pitch_value + channel_data[ channel_id ].pitch_addition - ( channel_data[ channel_id ].pitch_base << 0x10 ) ) / channel_data[ channel_id ].unknown_64; } channel_data[ channel_id ].unknown_d4 = channel_data[ channel_id ].pitch_selector; channel_data[ channel_id ].unknown_6a = channel_data[ channel_id ].saved_pitch; } else // 0xa0 { LOGGER->Log( " 0xA0 FINISH.\n" ); } } const u8 AkaoParser::NextSequenceHandle( ChannelData* channel_data, int channel_id, ChannelConfig& channel_config ) { u32 pointer = channel_data[ channel_id ].akao_sequence_pointer; u16 loop_index = channel_data[ channel_id ].loop_index; while( true ) { u8 opcode = m_Music->GetU8( pointer ); if( opcode < 0x9a ) { if( opcode >= 0x8f ) { channel_data[ channel_id ].unknown_6c = 0; channel_data[ channel_id ].unknown_6e &= 0xfffa; } return opcode; } if( opcode < 0xa0 ) { return 0xa0; } u8 size = opcode_size[ opcode - 0xa0 ]; if( size == 0 ) { switch( opcode ) { case 0xc9: { if( m_Music->GetU8( pointer + 1 ) == channel_data[ channel_id ].loop_count[ loop_index ] ) { pointer += 2; loop_index = (loop_index - 1) & 3; } else { pointer = channel_data[ channel_id ].loop_pointer[ loop_index ]; } continue; } break; case 0xca: { pointer = channel_data[ channel_id ].loop_pointer[ loop_index ]; continue; } break; case 0xcb: case 0xcd: case 0xd1: case 0xdb: { pointer += 1; channel_data[ channel_id ].unknown_6c = 0; channel_data[ channel_id ].unknown_6e &= 0xfffa; continue; } break; case 0xee: { pointer += 3 + ( s16 )( m_Music->GetU16LE( pointer + 1 ) ); continue; } break; case 0xef: { if( channel_config.conditional_value >= m_Music->GetU8( pointer + 1 ) ) { pointer += 4 + ( s16 )( m_Music->GetU16LE( pointer + 2 ) ); } else { pointer += 4; } continue; } break; case 0xf0: case 0xf1: { if( m_Music->GetU8( pointer + 1 ) == channel_data[ channel_id ].loop_count[ loop_index ] + 1 ) { loop_index = (loop_index - 1) & 3; pointer += 4 + ( s16 )( m_Music->GetU16LE( pointer + 2 ) ); } else { pointer += 4; } continue; } break; default: { channel_data[ channel_id ].unknown_6c = 0; channel_data[ channel_id ].unknown_6e &= 0xfffa; return 0xa0; } } } pointer += size; } } void AkaoParser::UpdateCounters( ChannelData* channel_data, int channel_id, ChannelConfig& channel_config ) { // update volume level if( channel_data[ channel_id ].volume_level_change_ticks != 0 ) { channel_data[ channel_id ].volume_level_change_ticks -= 1; s32 volume_level = channel_data[ channel_id ].volume_level + channel_data[ channel_id ].volume_level_add; if( ( volume_level & 0xffe0 ) != ( channel_data[ channel_id ].volume_level & 0xffe0 ) ) { channel_data[ channel_id ].spu_update_flags |= SPU_LEFT_VOLUME | SPU_RIGHT_VOLUME; } channel_data[ channel_id ].volume_level = volume_level; } if( channel_data[ channel_id ].unknown_c6_change_ticks != 0 ) { channel_data[ channel_id ].unknown_c6_change_ticks -= 1; u16 value = channel_data[ channel_id ].unknown_c6 + channel_data[ channel_id ].unknown_c8; if( channel_data[ channel_id ].mirror_update_flags & 0x00000100 ) { if( ( value & 0xff00 ) != ( channel_data[ channel_id ].unknown_c6 & 0xff00 ) ) { channel_data[ channel_id ].spu_update_flags |= SPU_LEFT_VOLUME | SPU_RIGHT_VOLUME; } } channel_data[ channel_id ].unknown_c6 = value; } /* if (hu[S0 + 62] != 0) { [S0 + 62] = h(hu[S0 + 62] - 1); A1 = hu[S0 + 60] + h[S0 + ca]; if ((A1 & ff00) != (hu[S0 + 60] & ff00)) { [S0 + e0] = w(w[S0 + e0] | 00000003); } [S0 + 60] = h(A1); } if (hu[S0 + 74] != 0) // wave1_delay_current { [S0 + 74] = h(hu[S0 + 74] - 1); } if (hu[S0 + 88] != 0) // wave2_delay_current { [S0 + 88] = h(hu[S0 + 88] - 1); } if (hu[S0 + a4] != 0) { [S0 + a4] = h(hu[S0 + a4] - 1); if (hu[S0 + a4] == 0) { channel_config.unknown_2c ^= ( 1 << channel_id ); [8009a13c] = w(w[8009a13c] | 00000010); func2ff4c; } } if (hu[S0 + a6] != 0) { [S0 + a4] = h(hu[S0 + a4] - 1); if (hu[S0 + a4] == 0) { channel_config.unknown_34 ^= ( 1 << channel_id ); 8002E660 jal func30148 [$80030148] } } if (hu[S0 + 80] != 0) { [S0 + 80] = h(hu[S0 + 80] - 1); [S0 + 7e] = h(hu[S0 + 7e] + hu[S0 + 82]); A0 = (hu[S0 + 7e] & 7f00) >> 8; if (hu[S0 + 7e] & 8000) { V0 = A0 * w[S0 + 30]; } else { V0 = A0 * ((w[S0 + 30] * f) >> 8); } [S0 + 7c] = h(V0 >> 7); if (hu[S0 + 74] == 0) { if (hu[S0 + 78] != 1) { A0 = w[S0 + 18]; if (h[A0 + 0] == 0) { if (h[A0 + 2] == 0) { A0 = A0 + h[A0 + 4] * 2; } } A1 = (hu[S0 + 7c] * h[A0]) >> 10; if (A1 != h[S0 + d6]) { [S0 + d6] = h(A1); [S0 + e0] = w(w[S0 + e0] | 00000010); if (A1 >= 0) { [S0 + d6] = h(A1 * 2); } } } } } if (hu[S0 + 92] != 0) { [S0 + 92] = h(hu[S0 + 92] - 1); [S0 + 90] = h(hu[S0 + 90] + hu[S0 + 94]); if (hu[S0 + 88] == 0) { if (hu[S0 + 8c] != 1) { A0 = w[S0 + 1c]; if (h[A0 + 0] == 0) { V0 = h[A0 + 2]; if (V0 == 0) { A0 = A0 + h[A0 + 4] * 2; } } A1 = ((((((h[S0 + 46] * w[S0 + 2c]) >> 7) * (hu[S0 + 90] >> 8)) << 9) >> 10) * h[A0]) >> f; if (A1 != h[S0 + d8]) { [S0 + e0] = w(w[S0 + e0] | 00000003); [S0 + d8] = h(A1); } } } } if (hu[S0 + a0] != 0) { [S0 + a0] = h(hu[S0 + a0] - 1); [S0 + 9e] = h(hu[S0 + 9e] + hu[S0 + a2]); if (hu[S0 + 9a] != 1) { A0 = w[S0 + 20]; if (h[A0 + 0] == 0) { if (h[A0 + 2] == 0) { A0 = A0 + h[A0 + 4] * 2; } } A1 = ((hu[S0 + 9e] >> 8) * h[A0]) >> f; if (A1 != h[S0 + da]) { [S0 + e0] = w(w[S0 + e0] | 00000003); [S0 + da] = h(A1); } } } if (hu[S0 + 64] != 0) { [S0 + 64] = h(hu[S0 + 64] - 1); A1 = w[S0 + 34] + w[S0 + 4c]; if ((A1 & ffff0000) != (w[S0 + 34] & ffff0000)) { [S0 + e0] = w(w[S0 + e0] | 00000010); } [S0 + 34] = w(A1); } */ } void AkaoParser::InitChannelInstrument( ChannelData* channel_data, int channel_id, int instrument_id ) { //LOGGER->Log( "Load voice " + Ogre::StringConverter::toString( instrument_id ) + " to channel " + Ogre::StringConverter::toString( channel_id ) + ".\n" ); InstrumentData data = m_InstrumentData[ instrument_id ]; channel_data[ channel_id ].instrument_id = instrument_id; channel_data[ channel_id ].start_offset = data.start_offset; channel_data[ channel_id ].loop_offset = data.loop_offset; //LOGGER->Log( "SPU_ADDRESS_START " + Ogre::StringConverter::toString( data.start_offset ) + "\n" ); //LOGGER->Log( "SPU_ADDRESS_LOOP " + Ogre::StringConverter::toString( data.loop_offset ) + "\n" ); channel_data[ channel_id ].attack_mode = data.attack_mode; channel_data[ channel_id ].sustain_mode = data.sustain_mode; channel_data[ channel_id ].release_mode = data.release_mode; channel_data[ channel_id ].attack_rate = data.attack_rate; channel_data[ channel_id ].decay_rate = data.decay_rate; channel_data[ channel_id ].sustain_level = data.sustain_level; channel_data[ channel_id ].sustain_rate = data.sustain_rate; channel_data[ channel_id ].release_rate = data.release_rate; channel_data[ channel_id ].spu_update_flags |= SPU_START_OFFSET | SPU_ATTACK_RATE | SPU_SUSTAIN_RATE | SPU_RELEASE_RATE | SPU_ATTACK_MODE | SPU_DECAY_RATE | SPU_SUSTAIN_MODE | SPU_RELEASE_MODE | SPU_SUSTAIN_LEVEL | SPU_LOOP_OFFSET; // update everything we just set } void AkaoParser::DumpSequenceData( const Ogre::String& file ) { std::ofstream oF; oF.open( file.c_str(), std::ios_base::binary | std::ios_base::out ); if ( !oF.is_open() ) { return; } oF << std::setfill( '0' ); oF << std::hex; oF << "*** Frame ID: 0x" << std::setw( 4 ) << m_Music->GetU16LE( 4 ) << std::endl; oF << std::dec; oF << "*** Frame Length: " << m_Music->GetU16LE( 6 ) << " bytes" << std::endl; oF << std::hex; oF << "*** Reverb Mode: 0x" << std::setw( 4 ) << m_Music->GetU16LE( 8 ) << std::endl; oF << std::endl; oF << std::hex; oF << "*** Channels mask: " <GetU32LE( 16 ) << std::endl << std::endl; for ( int i = 0; i < 24; ++i ) { if ( ( ( m_Music->GetU32LE( 16 ) ) & ( 1 << i ) ) == 0 ) { continue; } oF << std::dec; oF << "*** Channel " << std::setw( 2 ) << ( int )i << " sequence: " << std::endl; oF << std::hex; u16 j = 0; bool work = true; while ( work ) { u8 opcode = m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j ); switch ( opcode ) { case 0xa0: oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 0 ); oF << std::endl; work = false; break; // no parameters case 0xa6: case 0xa7: case 0xb3: case 0xb6: case 0xba: case 0xbe: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xd0: case 0xd1: case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xdb: case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xed: case 0xf3: case 0xf5: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xff: oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 0 ); oF << std::endl; ++j; break; // one parameter case 0xa1: case 0xa2: case 0xa3: case 0xa5: case 0xa8: case 0xaa: case 0xac: case 0xad: case 0xae: case 0xaf: case 0xb1: case 0xb2: case 0xb5: case 0xb7: case 0xb9: case 0xbb: case 0xbd: case 0xbf: case 0xc0: case 0xc1: case 0xc9: case 0xce: case 0xcf: case 0xd2: case 0xd3: case 0xd8: case 0xd9: case 0xda: case 0xdc: case 0xf2: case 0xf6: case 0xf8: oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 0 ) << ' '; oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 1 ); oF << std::endl; j += 2; break; // two parameters case 0xa4: case 0xa9: case 0xab: case 0xb0: case 0xbc: case 0xdd: case 0xde: case 0xdf: case 0xe8: case 0xea: case 0xec: case 0xee: case 0xf4: case 0xf7: case 0xfd: case 0xfe: oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 0 ) << ' '; oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 1 ) << ' '; oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 2 ); oF << std::endl; j += 3; break; // three parameters case 0xb4: case 0xb8: case 0xe9: case 0xeb: case 0xef: case 0xf0: case 0xf1: oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 0 ) << ' '; oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 1 ) << ' '; oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 2 ) << ' '; oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 3 ); oF << std::endl; j += 4; break; default: oF << std::setw( 2 ) << ( int )m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 0 ); if ( m_Music->GetU8( m_MusicChannelData[ i ].akao_sequence_pointer + j + 1 ) < 0xa0) { oF << ' '; } else { oF << std::endl; } ++j; } } oF << std::endl; } oF.close(); }