diff --git a/fm_banks/GENMIDI.GS.wopl b/fm_banks/GENMIDI.GS.wopl new file mode 100644 index 000000000..fb9646f94 Binary files /dev/null and b/fm_banks/GENMIDI.GS.wopl differ diff --git a/fm_banks/gs-by-papiezak-and-sneakernets.wopn b/fm_banks/gs-by-papiezak-and-sneakernets.wopn new file mode 100644 index 000000000..ecd87a53e Binary files /dev/null and b/fm_banks/gs-by-papiezak-and-sneakernets.wopn differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 30a98487b..b4ec9a4b9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -633,12 +633,9 @@ if( NOT SEND_ANON_STATS ) add_definitions( -DNO_SEND_STATS ) endif() -# OPLMIDI needs for USE_LEGACY_EMULATOR macro to be correctly built -add_definitions(-DOPNMIDI_USE_LEGACY_EMULATOR) - -# Disable ADLMIDI's and OPNMIDI's MIDI Sequencer, MUS and XMI converters -add_definitions(-DADLMIDI_DISABLE_MUS_SUPPORT -DADLMIDI_DISABLE_XMI_SUPPORT -DADLMIDI_DISABLE_MIDI_SEQUENCER) -add_definitions(-DOPNMIDI_DISABLE_MUS_SUPPORT -DOPNMIDI_DISABLE_XMI_SUPPORT -DOPNMIDI_DISABLE_MIDI_SEQUENCER) +# Disable ADLMIDI's and OPNMIDI's MIDI Sequencer +add_definitions(-DADLMIDI_DISABLE_MIDI_SEQUENCER) +add_definitions(-DOPNMIDI_DISABLE_MIDI_SEQUENCER) # Disable OPNMIDI's experimental yet emulator (using of it has some issues and missing notes in playback) add_definitions(-DOPNMIDI_DISABLE_GX_EMULATOR) @@ -876,6 +873,7 @@ set( FASTMATH_SOURCES sound/opnmidi/opnmidi_midiplay.cpp sound/opnmidi/opnmidi_opn2.cpp sound/opnmidi/opnmidi_private.cpp + sound/opnmidi/wopn/wopn_file.c ) @@ -1352,7 +1350,12 @@ endif() add_custom_command(TARGET zdoom POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_SOURCE_DIR}/soundfont/gzdoom.sf2 $/soundfonts/gzdoom.sf2) + ${CMAKE_SOURCE_DIR}/soundfont/gzdoom.sf2 $/soundfonts/gzdoom.sf2 + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_SOURCE_DIR}/fm_banks/GENMIDI.GS.wopl $/fm_banks/GENMIDI.GS.wopl + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_SOURCE_DIR}/fm_banks/gs-by-papiezak-and-sneakernets.wopn $/fm_banks/gs-by-papiezak-and-sneakernets.wopn +) if( CMAKE_COMPILER_IS_GNUCXX ) # GCC misoptimizes this file diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 37abce9d7..2979420f9 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -136,17 +136,27 @@ FGameConfigFile::FGameConfigFile () SetSection("SoundfontSearch.Directories", true); #ifdef __APPLE__ SetValueForKey("Path", user_docs + "/soundfonts", true); + SetValueForKey("Path", user_docs + "/fm_banks", true); SetValueForKey("Path", user_app_support + "/soundfonts", true); + SetValueForKey("Path", user_app_support + "/fm_banks", true); SetValueForKey("Path", "$PROGDIR/soundfonts", true); + SetValueForKey("Path", "$PROGDIR/fm_banks", true); SetValueForKey("Path", local_app_support + "/soundfonts", true); + SetValueForKey("Path", local_app_support + "/fm_banks", true); #elif !defined(__unix__) SetValueForKey("Path", "$PROGDIR/soundfonts", true); + SetValueForKey("Path", "$PROGDIR/fm_banks", true); #else SetValueForKey("Path", "$HOME/" GAME_DIR "/soundfonts", true); + SetValueForKey("Path", "$HOME/" GAME_DIR "/fm_banks", true); SetValueForKey("Path", "/usr/local/share/doom/soundfonts", true); + SetValueForKey("Path", "/usr/local/share/doom/fm_banks", true); SetValueForKey("Path", "/usr/local/share/games/doom/soundfonts", true); + SetValueForKey("Path", "/usr/local/share/games/doom/fm_banks", true); SetValueForKey("Path", "/usr/share/doom/soundfonts", true); + SetValueForKey("Path", "/usr/share/doom/fm_banks", true); SetValueForKey("Path", "/usr/share/games/doom/soundfonts", true); + SetValueForKey("Path", "/usr/share/games/doom/fm_banks", true); #endif } diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 19217e527..f7bf7e108 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -1382,10 +1382,12 @@ static void InitMusicMenus() { DMenuDescriptor **advmenu = MenuDescriptors.CheckKey("AdvSoundOptions"); auto soundfonts = sfmanager.GetList(); - std::tuple sfmenus[] = { std::make_tuple("GusConfigMenu", SF_SF2 | SF_GUS, "midi_config"), - std::make_tuple("WildMidiConfigMenu", SF_GUS, "wildmidi_config"), - std::make_tuple("TimidityConfigMenu", SF_SF2 | SF_GUS, "timidity_config"), - std::make_tuple("FluidPatchsetMenu", SF_SF2, "fluid_patchset") }; + std::tuple sfmenus[] = { std::make_tuple("GusConfigMenu", SF_SF2 | SF_GUS, "midi_config"), + std::make_tuple("WildMidiConfigMenu", SF_GUS, "wildmidi_config"), + std::make_tuple("TimidityConfigMenu", SF_SF2 | SF_GUS, "timidity_config"), + std::make_tuple("FluidPatchsetMenu", SF_SF2, "fluid_patchset"), + std::make_tuple("ADLMIDICustomBanksMenu", SF_WOPL, "adl_custom_bank"), + std::make_tuple("OPNMIDICustomBanksMenu", SF_WOPN, "opn_custom_bank")}; for (auto &p : sfmenus) { diff --git a/src/sound/adlmidi/adldata.cpp b/src/sound/adlmidi/adldata.cpp index 7215d7c89..558508975 100644 --- a/src/sound/adlmidi/adldata.cpp +++ b/src/sound/adlmidi/adldata.cpp @@ -4,7 +4,7 @@ * FROM A NUMBER OF SOURCES, MOSTLY PC GAMES. * PREPROCESSED, CONVERTED, AND POSTPROCESSED OFF-SCREEN. */ -const adldata adl[4537] = +const adldata adl[4528] = { // ,---------+-------- Wave select settings // | ,-------ч-+------ Sustain/release rates // | | ,-----ч-ч-+---- Attack/decay rates @@ -3969,8 +3969,8 @@ const adldata adl[4537] = { 0x185DC85,0x055F401, 0x91,0x0E, 0x3, +0 }, { 0x0F6E181,0x0F6E798, 0x00,0x2B, 0x1, +0 }, { 0x0F4F194,0x0A7E98A, 0x00,0x15, 0x1, +0 }, - { 0x0B3D407,0x0B4C202, 0xA0,0x00, 0xA, -12 }, - { 0x082D307,0x0E3A302, 0x58,0x80, 0xB, +0 }, + { 0x0B3D407,0x0B4C202, 0x9A,0x00, 0xA, -12 }, + { 0x082D307,0x0E3A302, 0x9A,0x00, 0xA, -12 }, { 0x156940A,0x132F411, 0xA7,0x05, 0x5, +0 }, { 0x027A2A0,0x023A522, 0x85,0x9E, 0x7, +0 }, { 0x02AA5A2,0x02AA168, 0x80,0x8F, 0x7, +0 }, @@ -3982,7 +3982,8 @@ const adldata adl[4537] = { 0x013C321,0x00B7022, 0x22,0x00, 0xE, +0 }, { 0x0F4F505,0x0F9F200, 0x29,0x1E, 0x6, +12 }, { 0x0F1F101,0x0F7F100, 0x2F,0x00, 0x6, +0 }, - { 0x0F4F405,0x0F6F100, 0x20,0x19, 0x6, +12 }, + { 0x0F4F405,0x0F6F110, 0x29,0x19, 0x6, +12 }, + { 0x0F1F111,0x0F7F100, 0x31,0x00, 0x6, +0 }, { 0x19F53C8,0x07FFAE4, 0x1C,0x03, 0x9, +0 }, { 0x0049420,0x0A5C523, 0x2A,0x24, 0xE, +12 }, { 0x0F9F200,0x0F8F101, 0x21,0x00, 0xE, +0 }, @@ -4005,15 +4006,20 @@ const adldata adl[4537] = { 0x0049100,0x2045240, 0x0F,0x00, 0x9, +0 }, { 0x0157620,0x0368261, 0x94,0x00, 0xC, +12 }, { 0x02661B1,0x0276171, 0xD3,0x80, 0xD, +0 }, + { 0x118543A,0x5177472, 0x1E,0x00, 0x4, -12 }, { 0x04A6121,0x00B7F21, 0x9F,0x00, 0xE, +0 }, { 0x00A65A1,0x0067F61, 0xA2,0x00, 0xF, +0 }, { 0x0277221,0x0067F21, 0x16,0x05, 0xC, +0 }, { 0x0866131,0x0D6C261, 0x1A,0x00, 0xE, +0 }, - { 0x0678221,0x0179222, 0x17,0x00, 0xE, +0 }, + { 0x0866131,0x0D6C261, 0x16,0x00, 0xF, +0 }, + { 0x0678221,0x0179222, 0x1A,0x00, 0xE, +0 }, + { 0x0678221,0x0179222, 0x15,0x0A, 0x7, +0 }, { 0x00AD961,0x006A861, 0x28,0x1E, 0xE, +0 }, { 0x0069A21,0x00ACF24, 0x25,0x00, 0xE, +0 }, { 0x02A9B32,0x0177221, 0x90,0x00, 0x4, +0 }, { 0x01CB632,0x01B66E1, 0x92,0x82, 0x5, +0 }, + { 0x00457F2,0x0375761, 0xA8,0x00, 0xE, +0 }, + { 0x2545C73,0x0776821, 0x00,0x0D, 0xE, +0 }, { 0x00FFF61,0x00FFF22, 0x1C,0x00, 0xE, +0 }, { 0x00FFF21,0x009CF62, 0x1C,0x00, 0xF, +0 }, { 0x0559622,0x0187421, 0x46,0x80, 0xF, +0 }, @@ -4023,31 +4029,50 @@ const adldata adl[4537] = { 0x2164460,0x00450E1, 0xAB,0x01, 0xB, +0 }, { 0x0022A55,0x0F34212, 0x97,0x86, 0x1, +0 }, { 0x1623524,0x1023171, 0x20,0x05, 0x1, +0 }, + { 0x155F261,0x0A5F242, 0x4D,0x00, 0x0, +0 }, + { 0x2343161,0x00532A1, 0x9D,0x80, 0xD, +0 }, { 0x011A131,0x0137D16, 0x87,0x08, 0x1, +0 }, - { 0x0F0A101,0x0437516, 0x0C,0x03, 0x1, +0 }, - { 0x053F201,0x052F317, 0x8F,0x09, 0x5, +0 }, + { 0x1127533,0x4F4F211, 0x58,0x03, 0x6, +0 }, + { 0x3F0F014,0x6F7F611, 0x40,0x43, 0xA, +0 }, + { 0x033F201,0x373F402, 0xD1,0x8A, 0x0, +0 }, + { 0x6A7F907,0x229A904, 0x1A,0x00, 0xA, -12 }, { 0x055C902,0x024A601, 0x1A,0x05, 0xD, +0 }, - { 0x0175E31,0x20C7B21, 0x18,0x08, 0x7, +0 }, + { 0x1397931,0x2099B22, 0x80,0x00, 0x6, +0 }, + { 0x2137931,0x1079B22, 0x42,0xC2, 0xA, +0 }, { 0x119FFA1,0x0089024, 0x0C,0x11, 0x7, +0 }, { 0x004F007,0x004F081, 0x51,0x13, 0x7, +0 }, { 0x026EC07,0x016F801, 0x15,0x00, 0xA, +0 }, { 0x001FF17,0x0057A12, 0x1C,0x0B, 0xB, +0 }, + { 0x4046306,0x005A902, 0xCA,0x08, 0x6, +0 }, + { 0x0045413,0x005A601, 0x51,0x08, 0xA, +0 }, { 0x09FF831,0x004FF10, 0x8B,0x05, 0x7, +0 }, + { 0x5C8FB00,0x0B7E601, 0x00,0x00, 0x0, +0 }, + { 0x2F0F00F,0x0F8F800, 0x00,0x40, 0xE, +12 }, { 0x001FF0E,0x20F2F01, 0x00,0x0D, 0xE, +0 }, - { 0x2077405,0x106F403, 0x80,0x0F, 0xF, +0 }, + { 0x0534313,0x7574A1F, 0x20,0x03, 0xE, -14 }, { 0x003FF15,0x0934511, 0x09,0x1F, 0xF, +0 }, - { 0x000200E,0x0022F0E, 0x00,0x0F, 0xF, +0 }, + { 0x200C327,0x6021300, 0x80,0x12, 0xE, -23 }, + { 0x200C32B,0x6021300, 0x80,0x12, 0xE, -24 }, { 0x060F209,0x072F214, 0x4F,0x19, 0xB, +0 }, { 0x1111EF0,0x11311E2, 0x00,0xC5, 0xF, +0 }, { 0x000FFEE,0x30318EE, 0x00,0x00, 0xE, +0 }, + { 0x059F802,0x01CF600, 0x11,0x00, 0xC, +0 }, + { 0x2159506,0x65AB701, 0x00,0x04, 0xE, +0 }, + { 0x10F5F81,0x0164611, 0x00,0x0A, 0x6, +0 }, + { 0x00F5F01,0x20F5F00, 0x00,0x00, 0x8, +0 }, + { 0x0D6D725,0x3A9A909, 0x1F,0x00, 0xE, -9 }, + { 0x0F0A00F,0x0F8F80F, 0x80,0x8C, 0xF, +0 }, + { 0x2FDFD00,0x6FAFA00, 0x00,0x00, 0xE, +0 }, + { 0x4F1F103,0x6FAFA07, 0x00,0x00, 0x8, +0 }, + { 0x0F0F007,0x2F6F60F, 0x27,0x00, 0x0, +21 }, { 0x0F7B710,0x005F011, 0x42,0x00, 0x8, +0 }, { 0x6EF8801,0x608B502, 0x0D,0x00, 0x0, +0 }, { 0x0F1F10F,0x007840F, 0x00,0x08, 0xC, +12 }, { 0x6EF8800,0x608F502, 0x13,0x00, 0x0, +8 }, { 0x0F1D101,0x0078400, 0x00,0x00, 0xE, +1 }, - { 0x254F307,0x307F905, 0x04,0x0B, 0x6, -5 }, - { 0x254F307,0x207F905, 0x04,0x0B, 0x8, +0 }, - { 0x25CD808,0x32B8A06, 0x04,0x08, 0xC, +0 }, + { 0x254F307,0x307F905, 0x04,0x08, 0x6, -5 }, + { 0x254F307,0x207F905, 0x04,0x08, 0x8, +0 }, + { 0x254D307,0x3288905, 0x04,0x03, 0xA, -5 }, { 0x2F2E327,0x3F5C525, 0x04,0x08, 0xA, -5 }, { 0x2F2F326,0x2F5C525, 0x04,0x08, 0x8, +0 }, { 0x292F108,0x354F201, 0x00,0x08, 0x8, +12 }, @@ -4057,17 +4082,24 @@ const adldata adl[4537] = { 0x251F206,0x263C504, 0x04,0x09, 0xA, +0 }, { 0x241F287,0x353B502, 0x05,0x09, 0xA, +1 }, { 0x292F108,0x354F201, 0x00,0x03, 0x8, +12 }, - { 0x456FB02,0x017F700, 0x81,0x00, 0x0, +12 }, - { 0x556FA01,0x117F701, 0x00,0x0D, 0x6, +10 }, - { 0x556FB02,0x117F701, 0x81,0x0D, 0x6, +10 }, - { 0x106F680,0x016F610, 0x00,0x00, 0xC, +0 }, - { 0x20F6F00,0x20F6F00, 0x00,0x00, 0x0, +0 }, - { 0x106F680,0x016F610, 0x00,0x00, 0x6, +0 }, - { 0x20F4F00,0x20F4F00, 0x00,0x00, 0x6, +0 }, - { 0x1DC5D01,0x06FF79F, 0x0B,0x00, 0xA, +12 }, - { 0x1C7C900,0x05FF49F, 0x07,0x00, 0xA, +12 }, + { 0x456FB02,0x017F700, 0x81,0x00, 0xC, +12 }, + { 0x556FA01,0x117F701, 0x00,0x0D, 0xA, +10 }, + { 0x556FB02,0x117F701, 0x81,0x0D, 0xA, +10 }, + { 0x0F00000,0x0F00000, 0x3F,0x3F, 0xC, +0 }, + { 0x000F020,0x40A8A00, 0x0A,0x00, 0xE, +0 }, + { 0x70F5F20,0x70F4F00, 0x00,0x00, 0x2, -12 }, + { 0x0D1F815,0x078F512, 0x44,0x00, 0x8, +12 }, + { 0x2D1F213,0x098F614, 0x9D,0x00, 0x0, +0 }, + { 0x2D1F213,0x098F614, 0x9D,0x21, 0x0, -2 }, + { 0x0985900,0x039870F, 0x07,0x00, 0x8, +13 }, + { 0x2F3F307,0x09C9B0F, 0x1D,0x00, 0x0, +13 }, + { 0x09C4B00,0x43A6705, 0x21,0x00, 0xC, +13 }, + { 0x0F7F907,0x2987805, 0x1C,0x00, 0x0, +13 }, { 0x3F0E00A,0x0F7F21F, 0x7C,0x40, 0x8, +0 }, { 0x3E0F50A,0x0FAF31F, 0x7C,0x40, 0x9, +0 }, + { 0x227A305,0x36A560A, 0x87,0x08, 0xE, +12 }, + { 0x247C345,0x3697809, 0x87,0x08, 0xE, +12 }, + { 0x037A309,0x06DF904, 0x11,0x00, 0xE, +0 }, { 0x1F5F213,0x0F5F111, 0xC6,0x0A, 0x0, +0 }, { 0x019F603,0x0F4F212, 0x30,0x10, 0xF, +0 }, { 0x1069FB2,0x10F94B0, 0xC0,0x86, 0x9, +0 }, @@ -4226,7 +4258,6 @@ const adldata adl[4537] = { 0x0235271,0x0198161, 0x1E,0x08, 0xE, +0 }, { 0x0235361,0x0196161, 0x1D,0x03, 0xE, +0 }, { 0x0155331,0x0378261, 0x94,0x00, 0xA, +0 }, - { 0x118543A,0x5177472, 0x1E,0x00, 0x4, -12 }, { 0x0365121,0x0257221, 0x1E,0x08, 0x0, +0 }, { 0x2844521,0x20592A0, 0x23,0x03, 0x0, +0 }, { 0x0578321,0x117C021, 0x19,0x03, 0xC, +0 }, @@ -4250,8 +4281,6 @@ const adldata adl[4537] = { 0x2176522,0x0277421, 0x5A,0x00, 0x6, +0 }, { 0x1267532,0x0166531, 0x8D,0x05, 0x4, +0 }, { 0x2F0F011,0x0987801, 0x03,0x17, 0xA, +0 }, - { 0x00457F2,0x0375761, 0xA8,0x00, 0xE, +0 }, - { 0x2545C73,0x0776821, 0x00,0x0D, 0xE, +0 }, { 0x5543737,0x25D67A1, 0x28,0x00, 0x8, +0 }, { 0x6243371,0x46D6331, 0x20,0x00, 0x6, +0 }, { 0x00F31D1,0x0053271, 0xC7,0x00, 0xB, +0 }, @@ -4304,35 +4333,22 @@ const adldata adl[4537] = { 0x2645321,0x2445521, 0x15,0x0D, 0xA, +0 }, { 0x0B37121,0x5F48221, 0x16,0x08, 0x2, +0 }, { 0x2B37102,0x5F48221, 0x90,0x08, 0x6, +0 }, - { 0x1127533,0x4F4F211, 0x58,0x03, 0x6, +0 }, - { 0x3F0F014,0x6F7F611, 0x40,0x43, 0xA, +0 }, - { 0x033F201,0x373F402, 0xD1,0x8A, 0x0, +0 }, - { 0x6A7F907,0x229A904, 0x1A,0x00, 0xA, -12 }, { 0x5E2F321,0x6E4F523, 0x1B,0x08, 0x8, +0 }, { 0x455F71C,0x0D68501, 0xA3,0x08, 0x6, +0 }, { 0x055F718,0x0D6E501, 0x23,0x08, 0x0, +0 }, - { 0x1397931,0x2099B22, 0x80,0x00, 0x6, +0 }, - { 0x2137931,0x1079B22, 0x42,0xC2, 0xA, +0 }, { 0x302A130,0x0266221, 0x1E,0x00, 0xE, +0 }, { 0x0136031,0x1169131, 0x12,0x80, 0x8, +0 }, { 0x032A115,0x172B212, 0x00,0x80, 0x1, +5 }, { 0x001E79A,0x067961C, 0x81,0x00, 0x4, +0 }, - { 0x4046306,0x005A902, 0xCA,0x08, 0x6, +0 }, - { 0x0045413,0x005A601, 0x51,0x08, 0xA, +0 }, { 0x4D1F214,0x098F715, 0xA0,0x00, 0xC, +0 }, { 0x008F312,0x004F600, 0x08,0xC8, 0x4, -12 }, { 0x27CFA01,0x004F200, 0x08,0x08, 0x0, +0 }, - { 0x5C8FB00,0x0B7E601, 0x00,0x00, 0x0, +0 }, - { 0x2F0F00F,0x0F8F800, 0x00,0x40, 0xE, +12 }, { 0x518F890,0x0E7F310, 0x00,0x00, 0x8, -12 }, { 0x250F610,0x0E7F510, 0x00,0xC8, 0x6, +0 }, { 0x2114109,0x51D2101, 0x05,0x80, 0xA, +0 }, { 0x2114108,0x31D2101, 0x05,0x80, 0xA, +12 }, - { 0x0534313,0x7574A1F, 0x20,0x03, 0xE, -14 }, { 0x00437D2,0x0343471, 0xA1,0x07, 0xC, +0 }, { 0x0F0F00C,0x0F66700, 0x00,0xCD, 0xE, +0 }, - { 0x200C327,0x6021300, 0x80,0x12, 0xE, -23 }, - { 0x200C32B,0x6021300, 0x80,0x12, 0xE, -24 }, { 0x003EBD7,0x06845D8, 0xD4,0x00, 0x7, +12 }, { 0x62FDA20,0x614B009, 0x42,0x48, 0x4, -24 }, { 0x62FDA20,0x614B009, 0x82,0x48, 0x4, -20 }, @@ -4341,15 +4357,7 @@ const adldata adl[4537] = { 0x200832F,0x6044020, 0x80,0x00, 0xE, -36 }, { 0x200832F,0x6044020, 0x80,0x00, 0xE, -35 }, { 0x2305431,0x6E7F600, 0x00,0x00, 0xE, +0 }, - { 0x059F802,0x01CF600, 0x11,0x00, 0xC, +0 }, - { 0x2159506,0x65AB701, 0x00,0x04, 0xE, +0 }, - { 0x10F5F81,0x0164611, 0x00,0x0A, 0x6, +0 }, - { 0x00F5F01,0x20F5F00, 0x00,0x00, 0x8, +0 }, - { 0x0D6D725,0x3A9A909, 0x1F,0x00, 0xE, -9 }, { 0x0F0A00F,0x0F8F80F, 0x00,0x0C, 0xE, +0 }, - { 0x2FDFD00,0x6FAFA00, 0x00,0x00, 0xE, +0 }, - { 0x4F1F103,0x6FAFA07, 0x00,0x00, 0x8, +0 }, - { 0x0F0F007,0x2F6F60F, 0x27,0x00, 0x0, +21 }, { 0x559FA00,0x047F800, 0x00,0x00, 0x4, +0 }, { 0x3F1F102,0x0078400, 0x00,0x26, 0xC, +0 }, { 0x048FA00,0x008F900, 0x00,0x00, 0x6, +12 }, @@ -4365,7 +4373,6 @@ const adldata adl[4537] = { 0x255F308,0x308F909, 0x04,0x08, 0x8, +4 }, { 0x006C604,0x007C604, 0x08,0x08, 0x1, +0 }, { 0x201F312,0x057AB09, 0x03,0x07, 0xC, +12 }, - { 0x254D307,0x3288905, 0x04,0x03, 0xA, -5 }, { 0x0015500,0x007C716, 0x0C,0x00, 0x0, +0 }, { 0x201F312,0x057AB09, 0x00,0x07, 0xC, +12 }, { 0x0015500,0x007C718, 0x0C,0x00, 0x0, +0 }, @@ -4393,9 +4400,6 @@ const adldata adl[4537] = { 0x0A5F7E9,0x0D8994A, 0x29,0x08, 0xC, +10 }, { 0x2A8F9E2,0x0779642, 0x1E,0x00, 0xE, +8 }, { 0x0A5F7E9,0x5D8994A, 0x08,0x00, 0xC, +0 }, - { 0x456FB02,0x017F700, 0x81,0x00, 0xC, +12 }, - { 0x556FA01,0x117F701, 0x00,0x0D, 0xA, +10 }, - { 0x556FB02,0x117F701, 0x81,0x0D, 0xA, +10 }, { 0x367FE06,0x668F701, 0x09,0x08, 0x8, +12 }, { 0x367FD10,0x098F901, 0x00,0x0D, 0x8, +6 }, { 0x367FE05,0x678F701, 0x09,0x08, 0x8, +12 }, @@ -4403,25 +4407,12 @@ const adldata adl[4537] = { 0x098600F,0x3FC8590, 0x08,0xC0, 0xE, +12 }, { 0x009F020,0x27DA788, 0x25,0x00, 0x0, +12 }, { 0x00FC020,0x22DA388, 0x25,0x00, 0xA, +12 }, - { 0x0F00000,0x0F00000, 0x3F,0x3F, 0xC, +0 }, - { 0x000F020,0x40A8A00, 0x0A,0x00, 0xE, +0 }, - { 0x70F5F20,0x70F4F00, 0x00,0x00, 0x2, -12 }, - { 0x0D1F815,0x078F512, 0x44,0x00, 0x8, +12 }, - { 0x2D1F213,0x098F614, 0x9D,0x00, 0x0, +0 }, - { 0x2D1F213,0x098F614, 0x9D,0x21, 0x0, -2 }, - { 0x0985900,0x039870F, 0x07,0x00, 0x8, +13 }, - { 0x2F3F307,0x09C9B0F, 0x1D,0x00, 0x0, +13 }, - { 0x09C4B00,0x43A6705, 0x21,0x00, 0xC, +13 }, - { 0x0F7F907,0x2987805, 0x1C,0x00, 0x0, +13 }, { 0x160F2C6,0x07AF4D4, 0x4F,0x80, 0x8, +12 }, { 0x160F286,0x0B7F294, 0x4F,0x80, 0x8, +12 }, - { 0x227A305,0x36A560A, 0x87,0x08, 0xE, +12 }, - { 0x247C345,0x3697809, 0x87,0x08, 0xE, +12 }, { 0x4755406,0x3667601, 0x87,0x08, 0x6, +12 }, { 0x275A346,0x3667601, 0x87,0x08, 0x6, +12 }, { 0x6E4840B,0x6E4B409, 0x12,0x09, 0x1, +0 }, { 0x6E4440B,0x6E46407, 0x21,0x13, 0x1, +3 }, - { 0x037A309,0x06DF904, 0x11,0x00, 0xE, +0 }, { 0x6F9A902,0x2F7C801, 0x00,0x40, 0x8, +0 }, { 0x4F9F901,0x4F7C713, 0x1F,0x48, 0x0, -7 }, { 0x4B7C720,0x1F3F300, 0x0B,0x00, 0x0, +0 }, @@ -4554,4822 +4545,4697 @@ const adldata adl[4537] = { 0x07BF003,0x07BF502, 0x8A,0x80, 0x8, +0 }, { 0x07BF003,0x07BF402, 0x8A,0x80, 0x8, +0 }, }; -const struct adlinsdata adlins[4804] = +const struct adlinsdata adlins[4678] = { - { 0, 0, 0, 0, 9006, 133,0 }, - { 1, 1, 0, 0, 9206, 146,0 }, - { 2, 2, 0, 0, 9246, 240,0 }, - { 3, 3, 0, 0, 9440, 140,0 }, - { 4, 4, 0, 0, 8900, 120,0 }, - { 5, 5, 0, 0, 9400, 140,0 }, - { 6, 6, 0, 0, 7460, 380,0 }, - { 7, 7, 0, 0, 9226, 93,0 }, - { 8, 8, 0, 0, 4613, 420,0 }, - { 9, 9, 0, 0, 7286, 4713,0 }, - { 10, 10, 0, 0, 2280, 746,0 }, - { 11, 11, 0, 0, 9233, 240,0 }, - { 12, 12, 0, 0, 346, 153,0 }, - { 13, 13, 0, 0, 633, 233,0 }, - { 14, 14, 0, 0, 4660, 1573,0 }, - { 15, 15, 0, 0, 1166, 400,0 }, - { 16, 16, 0, 0, 40000, 126,0 }, - { 17, 17, 0, 0, 40000, 93,0 }, - { 18, 18, 0, 0, 40000, 93,0 }, - { 19, 19, 0, 0, 40000, 553,0 }, - { 20, 20, 0, 0, 40000, 660,0 }, - { 21, 21, 0, 0, 40000, 73,0 }, - { 22, 22, 0, 0, 40000, 146,0 }, - { 23, 23, 0, 0, 40000, 146,0 }, - { 24, 24, 0, 0, 4026, 100,0 }, - { 25, 25, 0, 0, 14286, 120,0 }, - { 26, 26, 0, 0, 9233, 106,0 }, - { 27, 27, 0, 0, 4480, 100,0 }, - { 28, 28, 0, 0, 40000, 60,0 }, - { 29, 29, 0, 0, 40000, 80,0 }, - { 30, 30, 0, 0, 40000, 80,0 }, - { 31, 31, 0, 0, 18226, 100,0 }, - { 32, 32, 0, 0, 40000, 0,0 }, - { 33, 33, 0, 0, 40000, 80,0 }, - { 34, 34, 0, 0, 40000, 0,0 }, - { 35, 35, 0, 0, 40000, 53,0 }, - { 36, 36, 0, 0, 40000, 0,0 }, - { 37, 37, 0, 0, 40000, 0,0 }, - { 38, 38, 0, 0, 40000, 0,0 }, - { 39, 39, 0, 0, 40000, 160,0 }, - { 40, 40, 0, 0, 40000, 233,0 }, - { 41, 41, 0, 0, 40000, 73,0 }, - { 42, 42, 0, 0, 40000, 233,0 }, - { 43, 43, 0, 0, 40000, 213,0 }, - { 44, 44, 0, 0, 1246, 453,0 }, - { 45, 45, 0, 0, 4580, 786,0 }, - { 46, 46, 0, 0, 6873, 1246,0 }, - { 47, 47, 0, 0, 40000, 100,0 }, - { 48, 48, 0, 0, 40000, 140,0 }, - { 49, 49, 0, 0, 40000, 393,0 }, - { 50, 50, 0, 0, 40000, 406,0 }, - { 51, 51, 0, 0, 40000, 373,0 }, - { 52, 52, 0, 0, 40000, 0,0 }, - { 53, 53, 0, 0, 40000, 360,0 }, - { 54, 54, 0, 0, 1060, 380,0 }, - { 55, 55, 0, 0, 40000, 80,0 }, - { 56, 56, 0, 0, 40000, 73,0 }, - { 57, 57, 0, 0, 40000, 66,0 }, - { 58, 58, 0, 0, 40000, 60,0 }, - { 59, 59, 0, 0, 40000, 73,0 }, - { 60, 60, 0, 0, 40000, 66,0 }, - { 61, 61, 0, 0, 40000, 86,0 }, - { 62, 62, 0, 0, 40000, 66,0 }, - { 63, 63, 0, 0, 40000, 73,0 }, - { 64, 64, 0, 0, 40000, 80,0 }, - { 65, 65, 0, 0, 40000, 80,0 }, - { 66, 66, 0, 0, 40000, 73,0 }, - { 67, 67, 0, 0, 40000, 73,0 }, - { 68, 68, 0, 0, 40000, 53,0 }, - { 69, 69, 0, 0, 40000, 73,0 }, - { 70, 70, 0, 0, 40000, 126,0 }, - { 71, 71, 0, 0, 40000, 73,0 }, - { 72, 72, 0, 0, 40000, 73,0 }, - { 73, 73, 0, 0, 40000, 73,0 }, - { 74, 74, 0, 0, 40000, 66,0 }, - { 75, 75, 0, 0, 40000, 153,0 }, - { 76, 76, 0, 0, 40000, 153,0 }, - { 77, 77, 0, 0, 40000, 146,0 }, - { 78, 78, 0, 0, 40000, 146,0 }, - { 79, 79, 0, 0, 40000, 66,0 }, - { 80, 80, 0, 0, 40000, 60,0 }, - { 81, 81, 0, 0, 40000, 86,0 }, - { 82, 82, 0, 0, 40000, 73,0 }, - { 83, 83, 0, 0, 40000, 66,0 }, - { 84, 84, 0, 0, 40000, 153,0 }, - { 85, 85, 0, 0, 40000, 233,0 }, - { 86, 86, 0, 0, 40000, 80,0 }, - { 87, 87, 0, 0, 40000, 400,0 }, - { 88, 88, 0, 0, 40000, 1373,0 }, - { 89, 89, 0, 0, 40000, 193,0 }, - { 90, 90, 0, 0, 40000, 1273,0 }, - { 91, 91, 0, 0, 40000, 186,0 }, - { 92, 92, 0, 0, 40000, 86,0 }, - { 93, 93, 0, 0, 40000, 286,0 }, - { 94, 94, 0, 0, 40000, 140,0 }, - { 95, 95, 0, 0, 7440, 2473,0 }, - { 96, 96, 0, 0, 40000, 1220,0 }, - { 97, 97, 0, 0, 4946, 2713,0 }, - { 98, 98, 0, 0, 40000, 160,0 }, - { 99, 99, 0, 0, 8966, 406,0 }, - { 100, 100, 0, 0, 40000, 1353,0 }, - { 101, 101, 0, 0, 40000, 1306,0 }, - { 102, 102, 0, 0, 40000, 933,0 }, - { 103, 103, 0, 0, 9086, 226,0 }, - { 104, 104, 0, 0, 7233, 326,0 }, - { 105, 105, 0, 0, 7286, 200,0 }, - { 106, 106, 0, 0, 14180, 4406,0 }, - { 107, 107, 0, 0, 1180, 406,0 }, - { 108, 108, 0, 0, 40000, 66,0 }, - { 109, 109, 0, 0, 40000, 213,0 }, - { 110, 110, 0, 0, 40000, 73,0 }, - { 111, 111, 0, 0, 4606, 413,0 }, - { 112, 112, 0, 0, 613, 240,0 }, - { 113, 113, 0, 0, 1166, 400,0 }, - { 114, 114, 0, 0, 200, 353,0 }, - { 115, 115, 0, 0, 4553, 1480,0 }, - { 116, 116, 0, 0, 3740, 1260,0 }, - { 117, 117, 0, 0, 7240, 2300,0 }, - { 118, 118, 0, 0, 3020, 73,0 }, - { 119, 119, 0, 0, 1626, 800,0 }, - { 120, 120, 0, 0, 2466, 620,0 }, - { 121, 121, 0, 0, 12053, 3160,0 }, - { 122, 122, 0, 0, 466, 120,0 }, - { 123, 123, 0, 0, 1000, 320,0 }, - { 124, 124, 0, 0, 380, 60,0 }, - { 125, 125, 0, 0, 40000, 200,0 }, - { 126, 126, 0, 0, 560, 86,0 }, - { 127, 127, 35, 0, 386, 160,0 }, - { 128, 128, 52, 0, 126, 26,0 }, - { 129, 129, 48, 0, 286, 126,0 }, - { 130, 130, 58, 0, 173, 93,0 }, - { 129, 129, 60, 0, 286, 126,0 }, - { 131, 131, 47, 0, 520, 200,0 }, - { 132, 132, 43, 0, 173, 93,0 }, - { 131, 131, 49, 0, 520, 200,0 }, - { 133, 133, 43, 0, 160, 80,0 }, - { 131, 131, 51, 0, 526, 206,0 }, - { 134, 134, 43, 0, 1860, 653,0 }, - { 131, 131, 54, 0, 520, 200,0 }, - { 131, 131, 57, 0, 520, 200,0 }, - { 135, 135, 72, 0, 1860, 633,0 }, - { 131, 131, 60, 0, 506, 200,0 }, - { 136, 136, 76, 0, 1566, 546,0 }, - { 137, 137, 84, 0, 1340, 466,0 }, - { 138, 138, 36, 0, 1220, 433,0 }, - { 139, 139, 65, 0, 293, 133,0 }, - { 140, 140, 84, 0, 1333, 460,0 }, - { 141, 141, 83, 0, 220, 113,0 }, - { 135, 135, 84, 0, 1366, 473,0 }, - { 142, 142, 24, 0, 1893, 633,0 }, - { 136, 136, 77, 0, 1586, 553,0 }, - { 143, 143, 60, 0, 173, 93,0 }, - { 144, 144, 65, 0, 213, 126,0 }, - { 145, 145, 59, 0, 173, 0,0 }, - { 146, 146, 51, 0, 173, 100,0 }, - { 147, 147, 45, 0, 260, 206,0 }, - { 148, 148, 71, 0, 433, 180,0 }, - { 149, 149, 60, 0, 280, 26,0 }, - { 150, 150, 58, 0, 500, 186,0 }, - { 151, 151, 53, 0, 513, 200,0 }, - { 152, 152, 64, 0, 220, 86,0 }, - { 153, 153, 71, 0, 106, 46,0 }, - { 154, 154, 61, 0, 993, 340,0 }, - { 155, 155, 61, 0, 1906, 640,0 }, - { 156, 156, 44, 0, 206, 86,0 }, - { 157, 157, 40, 0, 586, 140,0 }, - { 158, 158, 69, 0, 126, 140,0 }, - { 159, 159, 68, 0, 126, 140,0 }, - { 160, 160, 63, 0, 146, 166,0 }, - { 161, 161, 74, 0, 280, 100,0 }, - { 162, 162, 60, 0, 1026, 320,0 }, - { 163, 163, 80, 0, 226, 100,0 }, - { 164, 164, 64, 0, 2713, 913,0 }, - { 165, 165, 72, 0, 120, 66,0 }, - { 166, 166, 73, 0, 386, 80,0 }, - { 167, 167, 70, 0, 553, 306,0 }, - { 168, 168, 68, 0, 126, 140,0 }, - { 169, 169, 48, 0, 386, 373,0 }, - { 131, 131, 53, 0, 520, 206,0 }, - { 170, 170, 0, 0, 40000, 0,0 }, - { 171, 171, 0, 0, 40000, 73,0 }, - { 172, 173, 0, 4, 5886, 100,0 }, - { 174, 175, 0, 4, 6913, 0,0 }, - { 176, 177, 0, 4, 4873, 0,0 }, - { 178, 178, 0, 0, 40000, 0,0 }, - { 179, 180, 0, 4, 4653, 433,0 }, - { 181, 181, 0, 0, 2280, 746,0 }, - { 182, 182, 0, 0, 40000, 0,0 }, - { 183, 184, 0, 4, 626, 0,0 }, - { 185, 186, 0, 4, 4653, 1546,0 }, - { 187, 187, 0, 0, 1166, 400,0 }, - { 188, 189, 0, 4, 40000, 60,0 }, - { 190, 191, 0, 4, 40000, 60,0 }, - { 192, 193, 0, 4, 40000, 73,0 }, - { 194, 194, 0, 0, 40000, 73,0 }, - { 195, 196, 0, 4, 40000, 66,0 }, - { 197, 198, 0, 4, 40000, 86,0 }, - { 199, 200, 0, 4, 40000, 66,0 }, - { 201, 202, 0, 4, 3713, 100,0 }, - { 203, 204, 0, 4, 14753, 126,0 }, - { 205, 206, 0, 4, 9286, 146,0 }, - { 207, 208, 0, 4, 14713, 126,0 }, - { 209, 210, 0, 4, 4653, 0,0 }, - { 211, 212, 0, 4, 40000, 66,0 }, - { 213, 213, 0, 0, 40000, 73,0 }, - { 214, 215, 0, 4, 626, 0,0 }, - { 216, 217, 0, 4, 4066, 100,0 }, - { 218, 219, 0, 4, 14586, 193,0 }, - { 220, 221, 0, 4, 2813, 106,0 }, - { 222, 223, 0, 4, 500, 0,0 }, - { 224, 224, 0, 0, 40000, 0,0 }, - { 225, 226, 0, 4, 7993, 93,0 }, - { 227, 227, 0, 0, 40000, 0,0 }, - { 228, 228, 0, 0, 40000, 133,0 }, - { 229, 230, 0, 4, 720, 213,0 }, - { 231, 232, 0, 4, 40000, 146,0 }, - { 233, 234, 0, 4, 40000, 0,0 }, - { 235, 236, 0, 4, 1000, 340,0 }, - { 235, 237, 0, 4, 3280, 1120,0 }, - { 46, 238, 0, 4, 6920, 0,0 }, - { 239, 240, 0, 4, 40000, 140,0 }, - { 241, 242, 0, 4, 40000, 146,0 }, - { 243, 243, 0, 0, 40000, 100,0 }, - { 244, 244, 0, 0, 40000, 60,0 }, - { 245, 245, 0, 0, 40000, 73,0 }, - { 246, 247, 0, 4, 720, 106,0 }, - { 248, 249, 0, 4, 40000, 126,0 }, - { 250, 250, 0, 0, 40000, 0,0 }, - { 251, 251, 0, 0, 40000, 126,0 }, - { 252, 253, 0, 4, 40000, 66,0 }, - { 254, 255, 0, 4, 40000, 93,0 }, - { 256, 257, 0, 4, 40000, 73,0 }, - { 258, 259, 0, 4, 40000, 86,0 }, - { 260, 261, 0, 4, 40000, 93,0 }, - { 262, 263, 0, 4, 40000, 80,0 }, - { 264, 265, 0, 4, 40000, 200,0 }, - { 266, 267, 0, 4, 40000, 73,0 }, - { 268, 269, 0, 4, 40000, 80,0 }, - { 270, 271, 0, 4, 40000, 73,0 }, - { 272, 273, 0, 4, 40000, 126,0 }, - { 274, 275, 0, 4, 40000, 100,0 }, - { 276, 276, 0, 0, 40000, 113,0 }, - { 277, 278, 0, 4, 40000, 186,0 }, - { 279, 280, 0, 4, 40000, 160,0 }, - { 281, 282, 0, 4, 40000, 206,0 }, - { 283, 283, 0, 0, 40000, 80,0 }, - { 284, 285, 0, 4, 40000, 73,0 }, - { 286, 287, 0, 4, 40000, 73,0 }, - { 288, 288, 0, 0, 40000, 93,0 }, - { 289, 290, 0, 4, 40000, 66,0 }, - { 291, 292, 0, 4, 40000, 153,0 }, - { 293, 294, 0, 4, 40000, 153,0 }, - { 295, 296, 0, 4, 40000, 320,0 }, - { 88, 297, 0, 4, 40000, 1280,0 }, - { 298, 299, 0, 4, 40000, 266,0 }, - { 300, 301, 0, 4, 40000, 1180,0 }, - { 302, 302, 0, 0, 40000, 286,0 }, - { 303, 303, 0, 0, 40000, 140,0 }, - { 304, 304, 0, 0, 13246, 2473,0 }, - { 305, 306, 0, 4, 40000, 1073,0 }, - { 307, 307, 0, 0, 9233, 240,0 }, - { 308, 308, 0, 0, 1186, 406,0 }, - { 309, 309, 0, 0, 40000, 1306,0 }, - { 310, 310, 0, 0, 40000, 933,0 }, - { 311, 312, 0, 4, 9146, 240,0 }, - { 313, 314, 0, 4, 7306, 326,0 }, - { 315, 316, 0, 4, 3586, 326,0 }, - { 317, 318, 0, 4, 7180, 0,0 }, - { 107, 319, 0, 4, 1180, 406,0 }, - { 108, 320, 0, 4, 40000, 66,0 }, - { 109, 321, 0, 4, 720, 213,0 }, - { 322, 323, 0, 4, 40000, 73,0 }, - { 324, 325, 0, 4, 613, 246,0 }, - { 326, 327, 0, 4, 1213, 386,0 }, - { 328, 328, 0, 0, 173, 106,0 }, - { 329, 329, 0, 0, 966, 333,0 }, - { 330, 331, 0, 4, 1906, 320,0 }, - { 332, 332, 0, 0, 3120, 73,0 }, - { 333, 333, 0, 0, 226, 73,0 }, - { 334, 334, 0, 0, 6600, 806,0 }, - { 335, 335, 0, 0, 273, 60,0 }, - { 336, 336, 0, 0, 12053, 660,0 }, - { 337, 337, 0, 0, 40000, 240,0 }, - { 338, 339, 0, 6, 6, 0,0 }, - { 340, 341, 0, 4, 560, 0,0 }, - { 342, 342, 35, 0, 40000, 0,0 }, - { 343, 343, 0, 0, 180, 100,0 }, - { 344, 344, 35, 0, 340, 146,0 }, - { 345, 345, 35, 0, 213, 33,0 }, - { 346, 346, 50, 0, 306, 20,0 }, - { 347, 347, 18, 0, 420, 146,0 }, - { 348, 348, 72, 0, 173, 86,0 }, - { 349, 349, 74, 0, 160, 93,0 }, - { 350, 350, 35, 0, 380, 146,0 }, - { 351, 351, 16, 0, 1206, 420,0 }, - { 352, 352, 0, 2, 6, 0,0 }, - { 353, 353, 38, 0, 200, 106,0 }, - { 354, 354, 38, 0, 346, 146,0 }, - { 355, 355, 31, 0, 406, 20,0 }, - { 355, 355, 35, 0, 406, 66,0 }, - { 355, 355, 38, 0, 406, 66,0 }, - { 355, 355, 41, 0, 406, 66,0 }, - { 355, 355, 45, 0, 306, 73,0 }, - { 355, 355, 50, 0, 306, 73,0 }, - { 356, 356, 36, 0, 1373, 493,0 }, - { 357, 357, 36, 0, 146, 33,0 }, - { 358, 358, 48, 0, 213, 86,0 }, - { 358, 358, 36, 0, 246, 86,0 }, - { 359, 359, 36, 0, 113, 0,0 }, - { 360, 360, 0, 0, 133, 40,0 }, - { 361, 361, 61, 0, 180, 26,0 }, - { 362, 362, 96, 0, 706, 266,0 }, - { 363, 363, 38, 0, 520, 193,0 }, - { 127, 127, 16, 0, 620, 233,0 }, - { 364, 365, 18, 4, 200, 0,0 }, - { 366, 366, 30, 0, 406, 246,0 }, - { 367, 368, 35, 4, 200, 0,0 }, - { 129, 129, 0, 0, 353, 153,0 }, - { 369, 369, 0, 0, 213, 13,0 }, - { 370, 370, 88, 0, 333, 113,0 }, - { 371, 371, 88, 0, 140, 73,0 }, - { 372, 372, 79, 0, 2540, 1040,0 }, - { 135, 135, 14, 0, 9213, 3066,0 }, - { 373, 373, 46, 0, 1093, 60,0 }, - { 374, 375,129, 4, 1200, 433,0 }, - { 376, 376, 58, 0, 1600, 726,0 }, - { 377, 377,164, 0, 526, 820,0 }, - { 378, 378,142, 0, 9153, 3073,0 }, - { 379, 379, 9, 0, 200, 100,0 }, - { 380, 381, 35, 4, 2353, 813,0 }, - { 382, 382, 28, 0, 1060, 120,0 }, - { 383, 383, 46, 0, 953, 20,0 }, - { 384, 384, 60, 0, 440, 160,0 }, - { 384, 384, 54, 0, 513, 180,0 }, - { 385, 385, 72, 0, 253, 120,0 }, - { 385, 385, 67, 0, 253, 113,0 }, - { 385, 385, 60, 0, 253, 106,0 }, - { 386, 386, 1, 0, 966, 613,0 }, - { 387, 387, 77, 0, 340, 86,0 }, - { 387, 387, 72, 0, 340, 86,0 }, - { 388, 388, 90, 0, 213, 86,0 }, - { 389, 389, 39, 0, 266, 73,0 }, - { 390, 390, 36, 0, 593, 73,0 }, - { 391, 392, 35, 4, 173, 46,0 }, - { 391, 393, 35, 4, 460, 66,0 }, - { 394, 394, 60, 0, 173, 20,0 }, - { 328, 328, 7, 0, 173, 0,0 }, - { 395, 395, 90, 0, 193, 20,0 }, - { 396, 396, 90, 0, 793, 40,0 }, - { 397, 397, 35, 0, 253, 86,0 }, - { 398, 399, 5, 4, 1913, 226,0 }, - { 400, 400,103, 0, 713, 273,0 }, - { 401, 401, 3, 0, 100, 0,0 }, - { 169, 169, 1, 0, 466, 413,0 }, - { 131, 131, 0, 0, 613, 226,0 }, - { 402, 402, 36, 0, 273, 53,0 }, - { 403, 403, 60, 0, 40000, 73,0 }, - { 404, 404, 37, 0, 1193, 426,0 }, - { 405, 405, 36, 0, 406, 20,0 }, - { 406, 406, 32, 0, 146, 73,0 }, - { 407, 407, 50, 0, 40000, 0,0 }, - { 408, 408, 50, 0, 793, 346,0 }, - { 409, 409, 83, 0, 120, 13,0 }, - { 410, 410, 72, 0, 433, 0,0 }, - { 148, 148, 59, 0, 513, 200,0 }, - { 411, 411, 64, 0, 173, 93,0 }, - { 411, 411, 60, 0, 173, 93,0 }, - { 412, 412, 72, 0, 160, 93,0 }, - { 412, 412, 62, 0, 173, 93,0 }, - { 413, 413, 83, 0, 773, 60,0 }, - { 414, 414, 0, 0, 40000, 80,0 }, - { 415, 415, 0, 0, 40000, 0,0 }, - { 416, 416, 0, 0, 40000, 73,0 }, - { 417, 417, 0, 0, 40000, 86,0 }, - { 418, 418, 0, 0, 40000, 0,0 }, - { 419, 419, 0, 0, 3440, 100,0 }, - { 420, 420, 0, 0, 3913, 420,0 }, - { 421, 421, 0, 0, 13620, 4640,0 }, - { 422, 422, 0, 0, 9233, 240,0 }, - { 423, 423, 0, 0, 633, 233,0 }, - { 424, 424, 0, 0, 4660, 1573,0 }, - { 425, 425, 0, 0, 4480, 1413,0 }, - { 426, 426, 0, 0, 40000, 0,0 }, - { 427, 427, 0, 0, 40000, 86,0 }, - { 428, 428, 60, 2, 6, 0,0 }, - { 429, 429, 73, 0, 593, 86,0 }, - { 429, 429, 74, 0, 593, 86,0 }, - { 429, 429, 80, 0, 593, 86,0 }, - { 429, 429, 84, 0, 593, 86,0 }, - { 429, 429, 92, 0, 520, 86,0 }, - { 430, 430, 81, 0, 786, 80,0 }, - { 430, 430, 83, 0, 786, 80,0 }, - { 430, 430, 95, 0, 680, 80,0 }, - { 431, 431, 35, 0, 593, 140,0 }, - { 432, 432, 60, 0, 213, 133,0 }, - { 357, 357, 59, 0, 113, 0,0 }, - { 432, 432, 44, 0, 213, 133,0 }, - { 433, 433, 41, 0, 713, 273,0 }, - { 434, 434, 97, 0, 113, 46,0 }, - { 433, 433, 44, 0, 513, 206,0 }, - { 433, 433, 48, 0, 506, 200,0 }, - { 435, 435, 96, 0, 700, 86,0 }, - { 433, 433, 51, 0, 520, 200,0 }, - { 433, 433, 54, 0, 513, 206,0 }, - { 436, 436, 40, 0, 1506, 793,0 }, - { 433, 433, 57, 0, 380, 160,0 }, - { 437, 437, 58, 0, 1600, 726,0 }, - { 438, 438, 97, 0, 233, 106,0 }, - { 439, 439, 50, 0, 186, 93,0 }, - { 437, 437, 60, 0, 1573, 713,0 }, - { 440, 440, 53, 0, 180, 73,0 }, - { 441, 441, 46, 0, 173, 126,0 }, - { 440, 440, 57, 0, 180, 40,0 }, - { 442, 442, 42, 0, 640, 240,0 }, - { 442, 442, 37, 0, 633, 233,0 }, - { 443, 443, 41, 0, 626, 240,0 }, - { 443, 443, 37, 0, 620, 233,0 }, - { 444, 444, 77, 0, 173, 40,0 }, - { 444, 444, 72, 0, 173, 40,0 }, - { 445, 445, 70, 0, 233, 100,0 }, - { 445, 445, 90, 0, 233, 93,0 }, - { 446, 446, 46, 0, 133, 73,0 }, - { 447, 447, 48, 0, 333, 73,0 }, - { 448, 448, 85, 0, 106, 0,0 }, - { 449, 449, 66, 0, 180, 26,0 }, - { 449, 449, 61, 0, 180, 26,0 }, - { 450, 450, 41, 0, 200, 66,0 }, - { 451, 451, 41, 0, 253, 66,0 }, - { 452, 452, 81, 0, 253, 26,0 }, - { 400, 400, 81, 0, 820, 306,0 }, - { 400, 400, 76, 0, 813, 300,0 }, - { 359, 359, 60, 0, 100, 0,0 }, - { 453, 453, 53, 0, 40000, 0,0 }, - { 454, 454, 0, 2, 6, 0,0 }, - { 455, 455, 0, 0, 200, 20,0 }, - { 456, 456, 0, 0, 4480, 100,0 }, - { 457, 457, 0, 0, 1180, 406,0 }, - { 458, 458, 0, 0, 40000, 86,0 }, - { 459, 459, 0, 0, 40000, 73,0 }, - { 460, 460, 0, 0, 3700, 66,0 }, - { 461, 461, 0, 0, 40000, 0,0 }, - { 462, 462, 0, 0, 6746, 2606,0 }, - { 463, 463, 0, 0, 40000, 213,0 }, - { 464, 464, 0, 0, 40000, 66,0 }, - { 465, 465, 0, 0, 40000, 100,0 }, - { 466, 466, 0, 0, 40000, 100,0 }, - { 467, 467, 0, 0, 5840, 806,0 }, - { 468, 468, 0, 0, 40000, 0,0 }, - { 469, 469, 0, 0, 40000, 0,0 }, - { 470, 470, 0, 0, 40000, 73,0 }, - { 471, 471, 0, 0, 40000, 133,0 }, - { 472, 472, 0, 0, 3320, 800,0 }, - { 473, 473, 0, 0, 40000, 173,0 }, - { 474, 474, 0, 0, 40000, 193,0 }, - { 475, 475, 0, 0, 2373, 800,0 }, - { 476, 476, 0, 0, 40000, 4986,0 }, - { 477, 477, 0, 0, 1180, 413,0 }, - { 478, 478, 0, 0, 3673, 1200,0 }, - { 479, 479, 0, 0, 973, 800,0 }, - { 480, 480, 0, 0, 7233, 2286,0 }, - { 481, 481, 0, 0, 40000, 73,0 }, - { 482, 482, 0, 0, 2526, 73,0 }, - { 483, 483, 0, 0, 393, 126,0 }, - { 484, 484, 0, 0, 40000, 200,0 }, - { 485, 485, 0, 0, 40000, 546,0 }, - { 486, 486, 0, 0, 1186, 413,0 }, - { 487, 487, 0, 0, 14166, 320,0 }, - { 488, 488, 0, 0, 8326, 646,0 }, - { 489, 489, 0, 0, 513, 206,0 }, - { 490, 490, 0, 0, 40000, 93,0 }, - { 491, 491, 50, 0, 1406, 353,0 }, - { 492, 492, 37, 0, 1040, 400,0 }, - { 493, 493, 39, 0, 406, 73,0 }, - { 494, 494, 39, 0, 3746, 860,0 }, - { 495, 495, 86, 0, 2133, 173,0 }, - { 496, 496, 43, 0, 140, 66,0 }, - { 127, 127, 24, 0, 513, 206,0 }, - { 127, 127, 29, 0, 520, 206,0 }, - { 497, 497, 50, 0, 340, 20,0 }, - { 498, 498, 30, 0, 5306, 1266,0 }, - { 498, 498, 33, 0, 3773, 886,0 }, - { 498, 498, 38, 0, 3746, 860,0 }, - { 498, 498, 42, 0, 3793, 906,0 }, - { 499, 499, 24, 0, 266, 0,0 }, - { 499, 499, 27, 0, 260, 153,0 }, - { 499, 499, 29, 0, 260, 153,0 }, - { 499, 499, 32, 0, 260, 153,0 }, - { 500, 500, 32, 0, 106, 0,0 }, - { 501, 501, 53, 0, 373, 186,0 }, - { 501, 501, 57, 0, 380, 193,0 }, - { 502, 502, 60, 0, 286, 133,0 }, - { 503, 503, 55, 0, 460, 126,0 }, - { 486, 486, 85, 0, 813, 293,0 }, - { 504, 504, 90, 0, 1580, 546,0 }, - { 505, 505, 84, 0, 246, 120,0 }, - { 506, 506, 48, 0, 826, 646,0 }, - { 507, 507, 48, 0, 266, 213,0 }, - { 132, 132, 72, 0, 126, 66,0 }, - { 508, 508, 72, 0, 106, 0,0 }, - { 509, 509, 72, 0, 100, 0,0 }, - { 510, 510, 63, 0, 1860, 633,0 }, - { 510, 510, 65, 0, 1853, 633,0 }, - { 511, 511, 79, 0, 1573, 553,0 }, - { 512, 512, 38, 0, 520, 793,0 }, - { 513, 513, 94, 0, 380, 160,0 }, - { 514, 514, 87, 0, 433, 306,0 }, - { 514, 514, 94, 0, 380, 273,0 }, - { 515, 515, 80, 0, 546, 273,0 }, - { 516, 516, 47, 0, 506, 200,0 }, - { 517, 517, 61, 0, 286, 133,0 }, - { 517, 517, 68, 0, 246, 120,0 }, - { 518, 518, 61, 0, 513, 206,0 }, - { 518, 518, 68, 0, 433, 180,0 }, - { 499, 499, 60, 0, 220, 133,0 }, - { 519, 519, 60, 0, 153, 46,0 }, - { 520, 520, 36, 0, 200, 20,0 }, - { 520, 520, 60, 0, 173, 20,0 }, - { 521, 521, 60, 0, 173, 20,0 }, - { 522, 522, 68, 0, 126, 26,0 }, - { 523, 523, 71, 0, 160, 186,0 }, - { 523, 523, 72, 0, 160, 186,0 }, - { 524, 524,101, 0, 966, 353,0 }, - { 525, 525, 36, 0, 3333, 480,0 }, - { 526, 526, 25, 0, 40000, 2293,0 }, - { 527, 527, 37, 0, 2106, 426,0 }, - { 528, 528, 36, 0, 720, 266,0 }, - { 528, 528, 41, 0, 713, 266,0 }, - { 529, 529, 84, 0, 173, 60,0 }, - { 530, 530, 54, 0, 40000, 0,0 }, - { 481, 481, 48, 0, 40000, 73,0 }, - { 531, 531, 0, 0, 10060, 1266,0 }, - { 532, 532, 0, 0, 4600, 606,0 }, - { 533, 533, 0, 0, 40000, 253,0 }, - { 534, 534, 0, 0, 40000, 73,0 }, - { 535, 535, 0, 0, 40000, 66,0 }, - { 536, 536, 0, 0, 40000, 80,0 }, - { 537, 537, 0, 0, 9413, 1393,0 }, - { 538, 538, 0, 0, 9000, 66,0 }, - { 539, 539, 0, 0, 40000, 0,0 }, - { 540, 540, 0, 0, 40000, 80,0 }, - { 541, 541, 0, 0, 40000, 120,0 }, - { 542, 542, 0, 0, 253, 73,0 }, - { 543, 543, 0, 0, 40000, 73,0 }, - { 544, 544, 0, 0, 18280, 800,0 }, - { 545, 545, 0, 0, 40000, 1133,0 }, - { 546, 546, 0, 0, 40000, 1226,0 }, - { 547, 547, 0, 0, 40000, 153,0 }, - { 135, 135, 49, 0, 3633, 1186,0 }, - { 548, 548, 35, 0, 2193, 80,0 }, - { 549, 549, 41, 0, 73, 0,0 }, - { 366, 366, 38, 0, 406, 246,0 }, - { 550, 550, 39, 0, 106, 20,0 }, - { 551, 551, 49, 0, 200, 133,0 }, - { 408, 408, 59, 0, 780, 326,0 }, - { 552, 552, 24, 0, 40000, 0,0 }, - { 552, 552, 27, 0, 40000, 0,0 }, - { 552, 552, 29, 0, 40000, 0,0 }, - { 552, 552, 32, 0, 40000, 0,0 }, - { 553, 553, 84, 0, 200, 33,0 }, - { 512, 512, 79, 0, 346, 460,0 }, - { 554, 554, 61, 0, 400, 126,0 }, - { 554, 554, 68, 0, 353, 120,0 }, - { 555, 555, 36, 0, 146, 86,0 }, - { 555, 555, 60, 0, 113, 0,0 }, - { 556, 556, 36, 0, 273, 53,0 }, - { 115, 115, 37, 0, 4580, 1513,0 }, - { 557, 557, 0, 0, 3806, 73,0 }, - { 558, 558, 0, 0, 40000, 0,0 }, - { 559, 559, 0, 0, 40000, 66,0 }, - { 560, 560, 0, 0, 5886, 133,0 }, - { 561, 561, 0, 0, 253, 26,0 }, - { 562, 562, 0, 0, 3246, 753,0 }, - { 563, 563, 0, 0, 40000, 100,0 }, - { 564, 564, 0, 0, 1620, 366,0 }, - { 565, 565, 0, 0, 40000, 0,0 }, - { 566, 566, 0, 0, 40000, 0,0 }, - { 567, 567, 0, 0, 40000, 0,0 }, - { 568, 568, 0, 0, 40000, 80,0 }, - { 569, 569, 0, 0, 760, 340,0 }, - { 570, 570, 0, 0, 40000, 0,0 }, - { 571, 571, 0, 0, 40000, 0,0 }, - { 572, 572, 0, 0, 40000, 0,0 }, - { 356, 356, 0, 0, 1893, 646,0 }, - { 573, 573, 0, 0, 40000, 93,0 }, - { 574, 574, 0, 0, 40000, 93,0 }, - { 575, 575, 0, 0, 40000, 200,0 }, - { 576, 576, 0, 0, 40000, 200,0 }, - { 577, 577, 0, 0, 40000, 126,0 }, - { 578, 578, 0, 0, 40000, 353,0 }, - { 579, 579, 0, 0, 40000, 346,0 }, - { 580, 580, 0, 0, 40000, 353,0 }, - { 581, 581, 0, 0, 40000, 100,0 }, - { 582, 582, 0, 0, 40000, 133,0 }, - { 583, 583, 0, 0, 2286, 713,0 }, - { 584, 584, 0, 0, 40000, 193,0 }, - { 585, 585, 0, 0, 40000, 0,0 }, - { 516, 516, 0, 0, 633, 240,0 }, - { 586, 586, 0, 0, 40000, 73,0 }, - { 587, 587, 0, 0, 40000, 73,0 }, - { 588, 588, 0, 0, 40000, 73,0 }, - { 498, 498, 26, 0, 5293, 1253,0 }, - { 494, 494, 35, 0, 3800, 913,0 }, - { 350, 350, 41, 0, 380, 153,0 }, - { 353, 353, 48, 0, 173, 100,0 }, - { 354, 354, 67, 0, 246, 120,0 }, - { 502, 502, 24, 0, 340, 146,0 }, - { 346, 346, 36, 0, 406, 73,0 }, - { 346, 346, 38, 0, 406, 20,0 }, - { 346, 346, 40, 0, 406, 73,0 }, - { 346, 346, 42, 0, 406, 20,0 }, - { 346, 346, 44, 0, 306, 20,0 }, - { 510, 510, 55, 0, 1866, 646,0 }, - { 346, 346, 46, 0, 306, 20,0 }, - { 136, 136, 80, 0, 1600, 573,0 }, - { 486, 486, 24, 0, 1193, 426,0 }, - { 153, 153, 50, 0, 106, 40,0 }, - { 346, 346, 24, 0, 540, 73,0 }, - { 516, 516, 31, 0, 626, 240,0 }, - { 498, 498, 35, 0, 3760, 880,0 }, - { 517, 517, 60, 0, 286, 133,0 }, - { 530, 530, 36, 0, 40000, 0,0 }, - { 530, 530, 48, 0, 40000, 0,0 }, - { 589, 589, 0, 0, 40000, 0,0 }, - { 139, 139, 76, 0, 253, 106,0 }, - { 156, 156, 48, 0, 206, 80,0 }, - { 157, 157, 48, 0, 426, 106,0 }, - { 165, 165, 69, 0, 120, 66,0 }, - { 167, 167, 75, 0, 546, 306,0 }, - { 590, 590, 0, 0, 40000, 0,0 }, - { 591, 591, 0, 0, 15486, 1580,0 }, - { 592, 592, 0, 0, 3446, 106,0 }, - { 593, 593, 0, 0, 1926, 146,0 }, - { 594, 594, 0, 0, 7293, 2380,0 }, - { 595, 595, 0, 0, 7613, 1566,0 }, - { 596, 596, 0, 0, 1153, 460,0 }, - { 597, 597, 0, 0, 1166, 400,0 }, - { 598, 598, 0, 0, 40000, 73,0 }, - { 599, 599, 0, 0, 40000, 766,0 }, - { 600, 600, 0, 0, 40000, 80,0 }, - { 601, 601, 0, 0, 1840, 513,0 }, - { 602, 602, 0, 0, 40000, 0,0 }, - { 603, 603, 0, 0, 4480, 733,0 }, - { 604, 604, 0, 0, 18226, 786,0 }, - { 605, 605, 0, 0, 4333, 233,0 }, - { 606, 606, 0, 0, 40000, 106,0 }, - { 607, 607, 0, 0, 40000, 366,0 }, - { 608, 608, 0, 0, 40000, 200,0 }, - { 609, 609, 0, 0, 713, 200,0 }, - { 610, 610, 0, 0, 8866, 1366,0 }, - { 611, 611, 0, 0, 2300, 73,0 }, - { 612, 612, 0, 0, 40000, 126,0 }, - { 613, 613, 0, 0, 40000, 1413,0 }, - { 614, 614, 0, 0, 40000, 333,0 }, - { 615, 615, 0, 0, 40000, 333,0 }, - { 616, 616, 0, 0, 40000, 26,0 }, - { 617, 617, 0, 0, 40000, 40,0 }, - { 618, 618, 0, 0, 4240, 353,0 }, - { 619, 619, 0, 0, 40000, 0,0 }, - { 620, 620, 0, 0, 40000, 73,0 }, - { 621, 621, 0, 0, 9020, 60,0 }, - { 622, 622, 0, 0, 3020, 0,0 }, - { 623, 623, 0, 0, 40000, 60,0 }, - { 624, 624, 0, 0, 40000, 73,0 }, - { 625, 625, 0, 0, 40000, 60,0 }, - { 626, 626, 0, 0, 40000, 53,0 }, - { 627, 627, 0, 0, 40000, 0,0 }, - { 628, 628, 0, 0, 40000, 66,0 }, - { 629, 629, 0, 0, 40000, 66,0 }, - { 630, 630, 0, 0, 5913, 426,0 }, - { 631, 631, 0, 0, 40000, 246,0 }, - { 632, 632, 0, 0, 40000, 206,0 }, - { 633, 633, 0, 0, 40000, 0,0 }, - { 634, 634, 0, 0, 2453, 780,0 }, - { 635, 635, 0, 0, 4740, 240,0 }, - { 636, 636, 0, 0, 1840, 353,0 }, - { 637, 637, 0, 0, 40000, 86,0 }, - { 638, 638, 0, 0, 3446, 1786,0 }, - { 346, 346, 0, 0, 540, 20,0 }, - { 639, 639, 0, 0, 7406, 2486,0 }, - { 404, 404, 0, 0, 1220, 466,0 }, - { 506, 506, 0, 0, 1000, 813,0 }, - { 639, 639, 60, 0, 2666, 913,0 }, - { 639, 639, 79, 0, 1366, 486,0 }, - { 640, 640, 65, 0, 2053, 646,0 }, - { 486, 486, 31, 0, 1206, 440,0 }, - { 486, 486, 36, 0, 1200, 433,0 }, - { 640, 640, 72, 0, 1713, 520,0 }, - { 136, 136, 79, 0, 1580, 560,0 }, - { 148, 148, 57, 0, 520, 206,0 }, - { 150, 150, 53, 0, 500, 193,0 }, - { 641, 641, 84, 0, 226, 66,0 }, - { 520, 520, 66, 0, 173, 20,0 }, - { 642, 642, 31, 0, 40000, 113,0 }, - { 642, 642, 29, 0, 40000, 113,0 }, - { 356, 356, 31, 0, 1366, 486,0 }, - { 356, 356, 19, 0, 1866, 633,0 }, - { 643, 643, 31, 0, 40000, 73,0 }, - { 643, 643, 29, 0, 40000, 73,0 }, - { 644, 644, 31, 0, 2286, 400,0 }, - { 644, 644, 35, 0, 2313, 420,0 }, - { 644, 644, 40, 0, 2353, 433,0 }, - { 644, 644, 47, 0, 1860, 346,0 }, - { 516, 516, 32, 0, 626, 240,0 }, - { 516, 516, 43, 0, 506, 200,0 }, - { 495, 495, 26, 0, 3180, 240,0 }, - { 495, 495, 44, 0, 2553, 206,0 }, - { 496, 496, 26, 0, 160, 73,0 }, - { 496, 496, 51, 0, 146, 66,0 }, - { 496, 496, 39, 0, 160, 73,0 }, - { 495, 495, 30, 0, 3180, 240,0 }, - { 645, 645, 44, 0, 1880, 653,0 }, - { 645, 645, 43, 0, 1886, 653,0 }, - { 646, 646, 0, 0, 2393, 833,0 }, - { 647, 647, 0, 0, 4693, 26,0 }, - { 648, 648, 0, 0, 2306, 773,0 }, - { 649, 649, 0, 0, 40000, 120,0 }, - { 650, 650, 0, 0, 40000, 66,0 }, - { 651, 651, 0, 0, 5866, 1206,0 }, - { 652, 652, 0, 0, 40000, 426,0 }, - { 653, 653, 0, 0, 1873, 633,0 }, - { 654, 654, 0, 0, 40000, 66,0 }, - { 655, 655, 0, 0, 40000, 73,0 }, - { 656, 656, 0, 0, 40000, 73,0 }, - { 657, 657, 0, 0, 40000, 0,0 }, - { 658, 658, 0, 0, 2040, 380,0 }, - { 659, 659, 0, 0, 40000, 73,0 }, - { 660, 660, 0, 0, 3720, 1260,0 }, - { 661, 661, 0, 0, 4080, 1046,0 }, - { 662, 662, 0, 0, 8693, 4666,0 }, - { 663, 663, 0, 0, 1926, 73,0 }, - { 664, 664, 0, 0, 8326, 646,0 }, - { 665, 665, 0, 0, 40000, 240,0 }, - { 666, 666, 0, 0, 40000, 226,0 }, - { 667, 667, 0, 0, 40000, 220,0 }, - { 668, 668, 0, 0, 40000, 0,0 }, - { 669, 669, 0, 0, 40000, 193,0 }, - { 670, 670, 0, 0, 880, 20,0 }, - { 671, 671, 0, 0, 4873, 120,0 }, - { 672, 672, 0, 0, 40000, 413,0 }, - { 673, 673, 0, 0, 700, 106,0 }, - { 674, 674, 0, 0, 700, 100,0 }, - { 675, 675, 0, 0, 40000, 126,0 }, - { 676, 676, 0, 0, 8113, 806,0 }, - { 677, 677, 0, 0, 8900, 80,0 }, - { 678, 678, 0, 0, 1893, 653,0 }, - { 679, 679, 0, 0, 3973, 206,0 }, - { 680, 680, 0, 0, 40000, 173,0 }, - { 681, 681, 0, 0, 40000, 73,0 }, - { 682, 682, 0, 0, 40000, 93,0 }, - { 683, 683, 0, 0, 1606, 640,0 }, - { 684, 684, 0, 0, 15486, 1580,0 }, - { 685, 685, 0, 0, 40000, 346,0 }, - { 686, 686, 0, 0, 40000, 786,0 }, - { 687, 687, 0, 0, 386, 240,0 }, - { 688, 688, 0, 0, 40000, 2066,0 }, - { 689, 689, 0, 0, 15453, 73,0 }, - { 690, 690, 0, 0, 1206, 240,0 }, - { 691, 691, 0, 0, 8866, 1366,0 }, - { 692, 692, 0, 0, 5913, 2253,0 }, - { 693, 693, 0, 0, 773, 106,0 }, - { 694, 694, 0, 0, 3793, 73,0 }, - { 695, 695, 0, 0, 40000, 73,0 }, - { 645, 645, 0, 0, 3633, 1180,0 }, - { 696, 696, 0, 0, 40000, 80,0 }, - { 697, 697, 0, 0, 40000, 0,0 }, - { 698, 698, 0, 0, 40000, 66,0 }, - { 699, 699, 0, 0, 40000, 66,0 }, - { 700, 700, 0, 0, 106, 0,0 }, - { 701, 701, 0, 0, 40000, 200,0 }, - { 702, 702, 0, 0, 3913, 73,0 }, - { 703, 703, 0, 0, 40000, 73,0 }, - { 704, 704, 0, 0, 40000, 73,0 }, - { 705, 705, 0, 0, 40000, 73,0 }, - { 706, 706, 0, 0, 40000, 66,0 }, - { 707, 707, 0, 0, 40000, 313,0 }, - { 708, 708, 0, 0, 40000, 100,0 }, - { 709, 709, 0, 0, 40000, 213,0 }, - { 710, 710, 0, 0, 40000, 53,0 }, - { 711, 711, 0, 0, 40000, 40,0 }, - { 712, 712, 0, 0, 40000, 73,0 }, - { 713, 713, 0, 0, 40000, 140,0 }, - { 714, 714, 0, 0, 40000, 606,0 }, - { 715, 715, 0, 0, 40000, 226,0 }, - { 716, 716, 0, 0, 3746, 1273,0 }, - { 717, 717, 0, 0, 40000, 80,0 }, - { 718, 718, 0, 0, 2360, 806,0 }, - { 719, 719, 0, 0, 1186, 420,0 }, - { 720, 720, 0, 0, 12533, 1953,0 }, - { 721, 721, 0, 0, 973, 1280,0 }, - { 722, 722, 0, 0, 40000, 426,0 }, - { 723, 723, 0, 0, 40000, 53,0 }, - { 724, 724, 0, 0, 40000, 66,0 }, - { 725, 725, 0, 0, 1246, 73,0 }, - { 726, 726, 0, 0, 3726, 1246,0 }, - { 727, 727, 0, 0, 2346, 813,0 }, - { 728, 728, 0, 0, 1206, 433,0 }, - { 507, 507, 0, 0, 306, 246,0 }, - { 512, 512, 0, 0, 526, 840,0 }, - { 729, 729, 0, 0, 14793, 4933,0 }, - { 730, 730, 0, 0, 14640, 4806,0 }, - { 731, 731, 0, 0, 5233, 633,0 }, - { 732, 732, 0, 0, 40000, 2513,0 }, - { 733, 733, 0, 0, 40000, 820,0 }, - { 734, 734, 0, 0, 40000, 0,0 }, - { 735, 735, 0, 0, 1726, 793,0 }, - { 736, 736, 0, 0, 513, 20,0 }, - { 737, 737, 0, 2, 6, 0,0 }, - { 738, 738, 38, 0, 1020, 413,0 }, - { 739, 739, 44, 0, 220, 33,0 }, - { 500, 500, 58, 0, 100, 0,0 }, - { 740, 740, 24, 0, 513, 206,0 }, - { 741, 741, 60, 0, 220, 26,0 }, - { 736, 736, 44, 0, 286, 20,0 }, - { 742, 742, 25, 0, 626, 246,0 }, - { 743, 743, 60, 0, 146, 86,0 }, - { 742, 742, 30, 0, 626, 240,0 }, - { 377, 377, 60, 0, 446, 626,0 }, - { 742, 742, 33, 0, 620, 226,0 }, - { 744, 744, 60, 0, 220, 113,0 }, - { 742, 742, 35, 0, 620, 233,0 }, - { 742, 742, 37, 0, 633, 246,0 }, - { 745, 745, 0, 0, 1880, 640,0 }, - { 742, 742, 40, 0, 640, 260,0 }, - { 746, 746,102, 0, 960, 300,0 }, - { 747, 747, 80, 0, 1106, 126,0 }, - { 377, 377, 0, 0, 500, 760,0 }, - { 748, 748, 56, 0, 100, 0,0 }, - { 749, 749, 0, 0, 973, 1300,0 }, - { 746, 746,100, 0, 960, 340,0 }, - { 750, 750, 40, 0, 626, 240,0 }, - { 750, 750, 35, 0, 626, 240,0 }, - { 751, 751, 29, 0, 206, 106,0 }, - { 750, 750, 29, 0, 633, 240,0 }, - { 750, 750, 22, 0, 640, 233,0 }, - { 500, 500, 0, 0, 106, 0,0 }, - { 752, 752, 0, 0, 206, 26,0 }, - { 753, 753, 84, 0, 166, 20,0 }, - { 754, 754, 84, 0, 1580, 553,0 }, - { 755, 755, 0, 0, 633, 233,0 }, - { 755, 755, 71, 0, 440, 180,0 }, - { 755, 755, 53, 0, 513, 200,0 }, - { 755, 755, 48, 0, 520, 206,0 }, - { 756, 756, 95, 0, 286, 20,0 }, - { 757, 757, 95, 0, 1880, 20,0 }, - { 758, 758, 0, 0, 14413, 333,0 }, - { 759, 759, 0, 0, 14453, 360,0 }, - { 760, 760, 0, 0, 14940, 353,0 }, - { 761, 761, 0, 0, 7286, 340,0 }, - { 762, 762, 0, 0, 14700, 60,0 }, - { 763, 763, 0, 0, 14506, 340,0 }, - { 764, 764, 0, 0, 14706, 200,0 }, - { 765, 765, 0, 0, 40000, 0,0 }, - { 766, 766, 0, 0, 2900, 426,0 }, - { 767, 767, 0, 0, 2986, 753,0 }, - { 768, 768, 0, 0, 1706, 680,0 }, - { 769, 769, 0, 0, 14646, 1253,0 }, - { 770, 770, 0, 0, 1713, 486,0 }, - { 771, 771, 0, 0, 966, 346,0 }, - { 772, 772, 0, 0, 3453, 766,0 }, - { 773, 773, 0, 0, 2866, 486,0 }, - { 774, 774, 0, 0, 40000, 73,0 }, - { 775, 775, 0, 0, 40000, 73,0 }, - { 776, 776, 0, 0, 40000, 166,0 }, - { 777, 777, 0, 0, 40000, 126,0 }, - { 778, 778, 0, 0, 40000, 113,0 }, - { 779, 779, 0, 0, 40000, 113,0 }, - { 780, 780, 0, 0, 40000, 93,0 }, - { 781, 781, 0, 0, 40000, 200,0 }, - { 782, 782, 0, 0, 7186, 93,0 }, - { 783, 783, 0, 0, 6406, 120,0 }, - { 784, 784, 0, 0, 40000, 0,0 }, - { 785, 785, 0, 0, 40000, 0,0 }, - { 786, 786, 0, 0, 1220, 73,0 }, - { 787, 787, 0, 0, 40000, 0,0 }, - { 788, 788, 0, 0, 17566, 66,0 }, - { 789, 789, 0, 0, 2333, 26,0 }, - { 790, 790, 0, 0, 4560, 153,0 }, - { 791, 791, 0, 0, 40000, 0,0 }, - { 792, 792, 0, 0, 40000, 0,0 }, - { 793, 793, 0, 0, 40000, 0,0 }, - { 794, 794, 0, 0, 2506, 126,0 }, - { 795, 795, 0, 0, 2513, 126,0 }, - { 796, 796, 0, 0, 40000, 0,0 }, - { 797, 797, 0, 0, 3386, 80,0 }, - { 798, 798, 0, 0, 40000, 100,0 }, - { 799, 799, 0, 0, 40000, 100,0 }, - { 800, 800, 0, 0, 40000, 120,0 }, - { 801, 801, 0, 0, 40000, 0,0 }, - { 802, 802, 0, 0, 40000, 200,0 }, - { 803, 803, 0, 0, 1080, 180,0 }, - { 804, 804, 0, 0, 3620, 1166,0 }, - { 805, 805, 0, 0, 1186, 393,0 }, - { 806, 806, 0, 0, 40000, 213,0 }, - { 807, 807, 0, 0, 40000, 426,0 }, - { 808, 808, 0, 0, 40000, 146,0 }, - { 809, 809, 0, 0, 40000, 146,0 }, - { 810, 810, 0, 0, 40000, 60,0 }, - { 811, 811, 0, 0, 40000, 113,0 }, - { 812, 812, 0, 0, 40000, 93,0 }, - { 813, 813, 0, 0, 1186, 153,0 }, - { 814, 814, 0, 0, 40000, 0,0 }, - { 815, 815, 0, 0, 40000, 80,0 }, - { 816, 816, 0, 0, 40000, 80,0 }, - { 817, 817, 0, 0, 40000, 46,0 }, - { 818, 818, 0, 0, 40000, 0,0 }, - { 819, 819, 0, 0, 40000, 66,0 }, - { 820, 820, 0, 0, 40000, 126,0 }, - { 821, 821, 0, 0, 40000, 213,0 }, - { 822, 822, 0, 0, 40000, 80,0 }, - { 823, 823, 0, 0, 40000, 73,0 }, - { 824, 824, 0, 0, 40000, 73,0 }, - { 825, 825, 0, 0, 40000, 100,0 }, - { 826, 826, 0, 0, 40000, 93,0 }, - { 827, 827, 0, 0, 40000, 73,0 }, - { 828, 828, 0, 0, 40000, 73,0 }, - { 829, 829, 0, 0, 40000, 80,0 }, - { 830, 830, 0, 0, 40000, 80,0 }, - { 831, 831, 0, 0, 40000, 80,0 }, - { 832, 832, 0, 0, 40000, 73,0 }, - { 833, 833, 0, 0, 40000, 80,0 }, - { 834, 834, 0, 0, 40000, 86,0 }, - { 835, 835, 0, 0, 40000, 100,0 }, - { 836, 836, 0, 0, 40000, 100,0 }, - { 837, 837, 0, 0, 40000, 140,0 }, - { 838, 838, 0, 0, 40000, 73,0 }, - { 839, 839, 0, 0, 40000, 0,0 }, - { 840, 840, 0, 0, 40000, 93,0 }, - { 841, 841, 0, 0, 40000, 0,0 }, - { 842, 842, 0, 0, 40000, 0,0 }, - { 843, 843, 0, 0, 40000, 73,0 }, - { 844, 844, 0, 0, 40000, 66,0 }, - { 845, 845, 0, 0, 40000, 0,0 }, - { 846, 846, 0, 0, 40000, 193,0 }, - { 847, 847, 0, 0, 40000, 340,0 }, - { 848, 848, 0, 0, 40000, 233,0 }, - { 849, 849, 0, 0, 40000, 80,0 }, - { 850, 850, 0, 0, 40000, 186,0 }, - { 851, 851, 0, 0, 9973, 426,0 }, - { 852, 852, 0, 0, 40000, 200,0 }, - { 853, 853, 0, 0, 40000, 400,0 }, - { 854, 854, 0, 0, 14633, 200,0 }, - { 855, 855, 0, 0, 40000, 333,0 }, - { 856, 856, 0, 0, 4620, 800,0 }, - { 857, 857, 0, 0, 8940, 386,0 }, - { 858, 858, 0, 0, 8966, 740,0 }, - { 859, 859, 0, 0, 40000, 273,0 }, - { 860, 860, 0, 0, 40000, 126,0 }, - { 861, 861, 0, 0, 40000, 400,0 }, - { 862, 862, 0, 0, 4480, 213,0 }, - { 863, 863, 0, 0, 633, 100,0 }, - { 864, 864, 0, 0, 3740, 353,0 }, - { 865, 865, 0, 0, 2333, 406,0 }, - { 866, 866, 0, 0, 1933, 566,0 }, - { 867, 867, 0, 0, 40000, 93,0 }, - { 868, 868, 0, 0, 40000, 106,0 }, - { 869, 869, 0, 0, 40000, 100,0 }, - { 870, 870, 0, 0, 3093, 240,0 }, - { 871, 871, 0, 0, 513, 93,0 }, - { 872, 872, 0, 0, 700, 180,0 }, - { 361, 361, 0, 0, 373, 40,0 }, - { 873, 873, 0, 0, 1046, 446,0 }, - { 874, 874, 0, 0, 1886, 520,0 }, - { 875, 875, 0, 0, 1226, 366,0 }, - { 876, 876, 0, 0, 4193, 73,0 }, - { 877, 877, 0, 0, 826, 120,0 }, - { 878, 878, 0, 0, 280, 146,0 }, - { 879, 879, 0, 0, 5266, 806,0 }, - { 880, 880, 0, 0, 386, 80,0 }, - { 881, 881, 0, 0, 40000, 100,0 }, - { 882, 882, 0, 0, 40000, 413,0 }, - { 883, 883, 0, 0, 40000, 0,0 }, - { 884, 884, 36, 0, 233, 80,0 }, - { 885, 885, 48, 0, 193, 93,0 }, - { 885, 885, 36, 0, 226, 100,0 }, - { 886, 886, 36, 0, 113, 0,0 }, - { 887, 887, 32, 0, 133, 40,0 }, - { 767, 767, 96, 0, 1760, 480,0 }, - { 888, 888, 30, 0, 246, 40,0 }, - { 889, 889, 35, 0, 420, 140,0 }, - { 890, 890, 60, 0, 240, 60,0 }, - { 884, 884, 59, 0, 146, 20,0 }, - { 890, 890, 44, 0, 240, 60,0 }, - { 891, 891, 41, 0, 713, 273,0 }, - { 892, 892, 47, 0, 173, 93,0 }, - { 891, 891, 44, 0, 513, 206,0 }, - { 891, 891, 48, 0, 506, 200,0 }, - { 893, 893, 62, 0, 1926, 93,0 }, - { 891, 891, 51, 0, 520, 200,0 }, - { 891, 891, 54, 0, 513, 206,0 }, - { 894, 894, 40, 0, 1280, 793,0 }, - { 891, 891, 57, 0, 380, 160,0 }, - { 895, 895, 97, 0, 233, 106,0 }, - { 896, 896, 50, 0, 220, 93,0 }, - { 376, 376, 60, 0, 1573, 713,0 }, - { 897, 897, 53, 0, 126, 73,0 }, - { 898, 898, 46, 0, 173, 133,0 }, - { 897, 897, 57, 0, 126, 33,0 }, - { 899, 899, 42, 0, 626, 233,0 }, - { 899, 899, 37, 0, 633, 240,0 }, - { 900, 900, 41, 0, 626, 240,0 }, - { 900, 900, 37, 0, 626, 240,0 }, - { 871, 871, 77, 0, 173, 40,0 }, - { 871, 871, 72, 0, 173, 40,0 }, - { 388, 388, 70, 0, 213, 86,0 }, - { 901, 901, 39, 0, 260, 26,0 }, - { 902, 902, 36, 0, 1093, 73,0 }, - { 903, 903, 46, 0, 120, 73,0 }, - { 904, 904, 48, 0, 766, 80,0 }, - { 905, 905, 85, 0, 126, 26,0 }, - { 361, 361, 66, 0, 180, 26,0 }, - { 906, 906, 41, 0, 193, 73,0 }, - { 907, 907, 41, 0, 333, 106,0 }, - { 908, 908, 81, 0, 160, 26,0 }, - { 400, 400, 10, 0, 1186, 413,0 }, - { 886, 886, 60, 0, 100, 0,0 }, - { 873, 873, 53, 0, 846, 360,0 }, - { 909, 909, 0, 0, 5593, 340,0 }, - { 910, 910, 0, 0, 14646, 346,0 }, - { 911, 911, 0, 0, 6826, 280,0 }, - { 912, 912, 0, 0, 7000, 306,0 }, - { 913, 913, 0, 0, 8793, 133,0 }, - { 914, 914, 0, 0, 14680, 346,0 }, - { 915, 915, 0, 0, 7246, 126,0 }, - { 916, 916, 0, 0, 40000, 0,0 }, - { 917, 917, 0, 0, 1866, 433,0 }, - { 362, 362, 0, 0, 1106, 340,0 }, - { 918, 918, 0, 0, 1053, 273,0 }, - { 919, 919, 0, 0, 14513, 1213,0 }, - { 920, 920, 0, 0, 1886, 646,0 }, - { 921, 921, 0, 0, 926, 313,0 }, - { 922, 922, 0, 0, 2340, 806,0 }, - { 923, 923, 0, 0, 2966, 553,0 }, - { 924, 924, 0, 0, 40000, 66,0 }, - { 925, 925, 0, 0, 40000, 73,0 }, - { 926, 926, 0, 0, 40000, 0,0 }, - { 927, 927, 0, 0, 40000, 126,0 }, - { 928, 928, 0, 0, 40000, 113,0 }, - { 929, 929, 0, 0, 40000, 113,0 }, - { 930, 930, 0, 0, 40000, 93,0 }, - { 931, 931, 0, 0, 40000, 113,0 }, - { 932, 932, 0, 0, 7200, 86,0 }, - { 933, 933, 0, 0, 5373, 106,0 }, - { 934, 934, 0, 0, 40000, 0,0 }, - { 935, 935, 0, 0, 40000, 0,0 }, - { 936, 936, 0, 0, 2380, 73,0 }, - { 937, 937, 0, 0, 40000, 0,0 }, - { 938, 938, 0, 0, 40000, 0,0 }, - { 939, 939, 0, 0, 6013, 53,0 }, - { 940, 940, 0, 0, 3713, 126,0 }, - { 941, 941, 0, 0, 17566, 26,0 }, - { 942, 942, 0, 0, 40000, 0,0 }, - { 943, 943, 0, 0, 40000, 0,0 }, - { 944, 944, 0, 0, 2506, 126,0 }, - { 945, 945, 0, 0, 3733, 73,0 }, - { 946, 946, 0, 0, 40000, 0,0 }, - { 947, 947, 0, 0, 3386, 80,0 }, - { 948, 948, 0, 0, 40000, 100,0 }, - { 949, 949, 0, 0, 40000, 100,0 }, - { 950, 950, 0, 0, 40000, 113,0 }, - { 951, 951, 0, 0, 40000, 0,0 }, - { 952, 952, 0, 0, 40000, 200,0 }, - { 953, 953, 0, 0, 1140, 213,0 }, - { 954, 954, 0, 0, 2140, 400,0 }, - { 955, 955, 0, 0, 813, 240,0 }, - { 956, 956, 0, 0, 40000, 100,0 }, - { 957, 957, 0, 0, 40000, 426,0 }, - { 958, 958, 0, 0, 40000, 0,0 }, - { 959, 959, 0, 0, 40000, 146,0 }, - { 960, 960, 0, 0, 40000, 120,0 }, - { 961, 961, 0, 0, 40000, 93,0 }, - { 962, 962, 0, 0, 1193, 153,0 }, - { 963, 963, 0, 0, 40000, 46,0 }, - { 964, 964, 0, 0, 40000, 80,0 }, - { 965, 965, 0, 0, 40000, 80,0 }, - { 966, 966, 0, 0, 40000, 20,0 }, - { 967, 967, 0, 0, 40000, 0,0 }, - { 968, 968, 0, 0, 40000, 93,0 }, - { 969, 969, 0, 0, 40000, 86,0 }, - { 970, 970, 0, 0, 40000, 213,0 }, - { 971, 971, 0, 0, 40000, 80,0 }, - { 972, 972, 0, 0, 40000, 73,0 }, - { 973, 973, 0, 0, 40000, 0,0 }, - { 974, 974, 0, 0, 40000, 93,0 }, - { 975, 975, 0, 0, 40000, 73,0 }, - { 976, 976, 0, 0, 40000, 73,0 }, - { 977, 977, 0, 0, 40000, 66,0 }, - { 978, 978, 0, 0, 40000, 66,0 }, - { 979, 979, 0, 0, 40000, 100,0 }, - { 980, 980, 0, 0, 40000, 73,0 }, - { 981, 981, 0, 0, 40000, 73,0 }, - { 982, 982, 0, 0, 40000, 80,0 }, - { 983, 983, 0, 0, 40000, 100,0 }, - { 984, 984, 0, 0, 40000, 100,0 }, - { 985, 985, 0, 0, 40000, 100,0 }, - { 986, 986, 0, 0, 40000, 80,0 }, - { 987, 987, 0, 0, 40000, 73,0 }, - { 988, 988, 0, 0, 40000, 0,0 }, - { 989, 989, 0, 0, 40000, 86,0 }, - { 990, 990, 0, 0, 40000, 0,0 }, - { 991, 991, 0, 0, 40000, 0,0 }, - { 992, 992, 0, 0, 40000, 80,0 }, - { 993, 993, 0, 0, 40000, 86,0 }, - { 994, 994, 0, 0, 40000, 0,0 }, - { 995, 995, 0, 0, 40000, 0,0 }, - { 996, 996, 0, 0, 40000, 333,0 }, - { 997, 997, 0, 0, 40000, 180,0 }, - { 998, 998, 0, 0, 40000, 80,0 }, - { 999, 999, 0, 0, 40000, 120,0 }, - {1000,1000, 0, 0, 10006, 460,0 }, - {1001,1001, 0, 0, 40000, 186,0 }, - {1002,1002, 0, 0, 40000, 400,0 }, - {1003,1003, 0, 0, 20333, 260,0 }, - {1004,1004, 0, 0, 40000, 373,0 }, - {1005,1005, 0, 0, 4520, 400,0 }, - {1006,1006, 0, 0, 8213, 306,0 }, - {1007,1007, 0, 0, 8646, 360,0 }, - {1008,1008, 0, 0, 40000, 160,0 }, - {1009,1009, 0, 0, 40000, 133,0 }, - {1010,1010, 0, 0, 40000, 400,0 }, - {1011,1011, 0, 0, 4473, 193,0 }, - {1012,1012, 0, 0, 1813, 0,0 }, - {1013,1013, 0, 0, 3726, 353,0 }, - {1014,1014, 0, 0, 4400, 373,0 }, - {1015,1015, 0, 0, 953, 166,0 }, - {1016,1016, 0, 0, 40000, 73,0 }, - {1017,1017, 0, 0, 40000, 100,0 }, - {1018,1018, 0, 0, 40000, 100,0 }, - {1019,1019, 0, 0, 3100, 240,0 }, - { 444, 444, 0, 0, 513, 93,0 }, - {1020,1020, 0, 0, 626, 180,0 }, - { 449, 449, 0, 0, 373, 80,0 }, - { 453, 453, 0, 0, 40000, 0,0 }, - {1021,1021, 0, 0, 1020, 340,0 }, - {1022,1022, 0, 0, 1200, 366,0 }, - {1023,1023, 0, 0, 4193, 73,0 }, - {1024,1024, 0, 0, 820, 120,0 }, - {1025,1025, 0, 0, 680, 213,0 }, - {1026,1026, 0, 0, 5260, 806,0 }, - {1027,1027, 0, 0, 9193, 86,0 }, - {1028,1028, 0, 0, 40000, 100,0 }, - {1029,1029, 0, 0, 40000, 426,0 }, - {1030,1030, 0, 0, 40000, 260,0 }, - {1031,1031, 0, 0, 3480, 66,0 }, - {1032,1032, 32, 0, 133, 46,0 }, - {1033,1033, 30, 0, 200, 40,0 }, - {1034,1034, 96, 0, 146, 73,0 }, - {1035,1035, 60, 0, 553, 186,0 }, - {1036,1036, 0, 0, 13193, 260,0 }, - {1037,1037, 0, 0, 40000, 100,0 }, - {1038,1038, 0, 0, 7980, 66,0 }, - {1039,1039, 0, 0, 40000, 0,0 }, - {1040,1040, 0, 0, 980, 340,0 }, - {1041,1041, 0, 0, 7413, 2480,0 }, - {1042,1042, 0, 0, 2906, 520,0 }, - {1043,1043, 0, 0, 40000, 73,0 }, - {1044,1044, 0, 0, 40000, 53,0 }, - {1045,1045, 0, 0, 40000, 113,0 }, - {1046,1046, 0, 0, 5380, 113,0 }, - {1047,1047, 0, 0, 40000, 0,0 }, - {1048,1048, 0, 0, 2366, 73,0 }, - {1049,1049, 0, 0, 40000, 0,0 }, - {1050,1050, 0, 0, 18293, 80,0 }, - {1051,1051, 0, 0, 18466, 146,0 }, - {1052,1052, 0, 0, 9220, 73,0 }, - {1053,1053, 0, 0, 40000, 240,0 }, - {1054,1054, 0, 0, 40000, 0,0 }, - {1055,1055, 0, 0, 1086, 126,0 }, - {1056,1056, 0, 0, 3766, 73,0 }, - {1057,1057, 0, 0, 1186, 226,0 }, - {1058,1058, 0, 0, 3373, 73,0 }, - {1059,1059, 0, 0, 40000, 246,0 }, - {1060,1060, 0, 0, 340, 220,0 }, - {1061,1061, 0, 0, 1186, 386,0 }, - {1062,1062, 0, 0, 40000, 253,0 }, - {1063,1063, 0, 0, 40000, 440,0 }, - {1064,1064, 0, 0, 40000, 46,0 }, - {1065,1065, 0, 0, 40000, 80,0 }, - {1066,1066, 0, 0, 40000, 126,0 }, - {1067,1067, 0, 0, 40000, 133,0 }, - {1068,1068, 0, 0, 40000, 93,0 }, - {1069,1069, 0, 0, 40000, 86,0 }, - {1070,1070, 0, 0, 40000, 93,0 }, - {1071,1071, 0, 0, 40000, 66,0 }, - {1072,1072, 0, 0, 40000, 93,0 }, - {1073,1073, 0, 0, 40000, 73,0 }, - {1074,1074, 0, 0, 40000, 173,0 }, - {1075,1075, 0, 0, 586, 193,0 }, - {1076,1076, 0, 0, 40000, 146,0 }, - {1077,1077, 0, 0, 18460, 73,0 }, - {1078,1078, 0, 0, 846, 93,0 }, - {1079,1079, 0, 0, 40000, 0,0 }, - {1080,1080, 0, 0, 40000, 86,0 }, - {1081,1081, 0, 0, 40000, 0,0 }, - {1082,1082, 0, 0, 40000, 353,0 }, - {1083,1083, 0, 0, 40000, 300,0 }, - {1084,1084, 0, 0, 40000, 320,0 }, - {1085,1085, 0, 0, 9920, 1553,0 }, - {1086,1086, 0, 0, 40000, 386,0 }, - {1087,1087, 0, 0, 40000, 0,0 }, - {1088,1088, 0, 0, 9980, 873,0 }, - {1089,1089, 0, 0, 40000, 386,0 }, - {1090,1090, 0, 0, 966, 126,0 }, - {1091,1091, 0, 0, 40000, 820,0 }, - {1092,1092, 0, 0, 8620, 366,0 }, - {1093,1093, 0, 0, 40000, 826,0 }, - {1094,1094, 0, 0, 40000, 433,0 }, - {1095,1095, 0, 0, 633, 73,0 }, - {1096,1096, 0, 0, 3693, 126,0 }, - {1097,1097, 0, 0, 40000, 0,0 }, - {1098,1098, 0, 0, 40000, 153,0 }, - {1099,1099, 0, 0, 40000, 0,0 }, - {1100,1100, 0, 0, 40000, 0,0 }, - {1101,1101, 0, 0, 40000, 306,0 }, - {1102,1102, 0, 0, 3666, 3093,0 }, - {1103,1103, 0, 0, 1873, 653,0 }, - {1104,1104, 0, 0, 40000, 0,0 }, - {1105,1105, 0, 0, 11293, 886,0 }, - {1106,1106, 0, 0, 40000, 546,0 }, - { 430, 430, 0, 0, 1146, 80,0 }, - {1107,1107, 35, 0, 580, 80,0 }, - {1090,1090, 77, 0, 280, 60,0 }, - {1090,1090, 72, 0, 280, 60,0 }, - {1108,1108, 0, 0, 10180, 600,0 }, - {1109,1109, 0, 0, 10053, 353,0 }, - {1110,1111, 0, 1, 9940, 480,0 }, - {1112,1113, 0, 1, 10620, 473,0.03125 }, - {1114,1114, 0, 0, 40000, 0,0 }, - {1115,1116, 0, 1, 9833, 220,0 }, - {1117,1117, 0, 0, 10286, 473,0 }, - {1118,1118, 0, 0, 7686, 93,0 }, - {1119,1119, 0, 0, 7220, 613,0 }, - {1120,1120, 0, 0, 11513, 1666,0 }, - {1121,1121, 0, 0, 5200, 1700,0 }, - {1122,1122, 0, 0, 10173, 626,0 }, - {1123,1123, 0, 0, 1206, 380,0 }, - {1124,1124, 0, 0, 1953, 866,0 }, - {1125,1125, 0, 0, 4686, 1586,0 }, - {1126,1126, 0, 0, 3786, 893,0 }, - {1127,1127, 0, 0, 40000, 126,0 }, - {1128,1128, 0, 0, 40000, 120,0 }, - {1129,1130, 0, 1, 40000, 146,0.15625 }, - {1131,1131, 0, 0, 40000, 433,0 }, - {1132,1132, 0, 0, 40000, 133,0 }, - {1133,1134, 0, 1, 40000, 126,-0.046875 }, - {1135,1135, 0, 0, 40000, 113,0 }, - {1136,1137, 0, 1, 40000, 253,2.5e-05 }, - {1138,1138, 0, 0, 18440, 240,0 }, - {1139,1139, 0, 0, 5213, 886,0 }, - {1140,1140, 0, 0, 1446, 113,0 }, - {1141,1141, 0, 0, 5233, 106,0 }, - {1142,1142, 0, 0, 5286, 266,0 }, - {1143,1143, 0, 0, 40000, 66,0 }, - {1144,1144, 0, 0, 40000, 66,0 }, - {1145,1145, 0, 0, 10593, 106,0 }, - {1146,1146, 0, 0, 2733, 160,0 }, - {1147,1147, 0, 0, 10313, 93,0 }, - {1148,1148, 0, 0, 40000, 0,0 }, - {1149,1150, 0, 1, 40000, 0,-0.03125 }, - {1151,1151, 0, 0, 40000, 53,0 }, - {1152,1152, 0, 0, 10560, 246,0 }, - {1153,1153, 0, 0, 2700, 153,0 }, - {1154,1154, 0, 1, 40000, 100,-0.15625 }, - {1155,1155, 0, 0, 40000, 73,0 }, - {1156,1156, 0, 0, 40000, 220,0 }, - {1157,1157, 0, 0, 40000, 140,0 }, - {1158,1158, 0, 0, 40000, 380,0 }, - {1159,1160, 0, 1, 40000, 400,0.171875 }, - {1161,1161, 0, 0, 40000, 0,0 }, - {1162,1162, 0, 0, 40000, 0,0 }, - {1163,1163, 0, 0, 4733, 906,0 }, - {1164,1165, 0, 1, 40000, 393,-0.125 }, - {1166,1167, 0, 1, 40000, 366,0.078125 }, - {1168,1168, 0, 1, 40000, 2453,-0.078125 }, - {1169,1170, 0, 1, 40000, 546,0.0625 }, - {1171,1172, 0, 1, 40000, 786,0.15625 }, - {1173,1173, 0, 0, 40000, 0,0 }, - {1174,1174, 0, 0, 40000, 513,0 }, - {1175,1176, 0, 1, 2300, 533,0 }, - {1177,1177, 0, 0, 40000, 80,0 }, - {1178,1178, 0, 0, 40000, 60,0 }, - {1179,1179, 0, 0, 40000, 0,0 }, - {1180,1180, 0, 0, 10653, 86,0 }, - {1181,1182, 0, 1, 40000, 0,2.5e-05 }, - {1183,1184, 0, 1, 40000, 86,0.046875 }, - {1185,1186, 0, 1, 40000, 0,0.09375 }, - {1187,1188, 0, 1, 40000, 0,0.09375 }, - {1189,1189, 0, 0, 40000, 133,0 }, - {1190,1190, 0, 0, 40000, 140,0 }, - {1191,1191, 0, 0, 40000, 73,0 }, - {1192,1192, 0, 0, 40000, 60,0 }, - {1193,1193, 0, 0, 40000, 106,0 }, - {1194,1194, 0, 0, 40000, 93,0 }, - {1195,1195, 0, 0, 40000, 66,0 }, - {1196,1196, 0, 0, 40000, 93,0 }, - {1197,1197, 0, 0, 40000, 60,0 }, - {1198,1198, 0, 0, 40000, 66,0 }, - {1199,1199, 0, 0, 40000, 120,0 }, - {1200,1200, 0, 0, 40000, 100,0 }, - {1201,1201, 0, 0, 40000, 86,0 }, - {1202,1202, 0, 0, 40000, 0,0 }, - {1203,1203, 0, 0, 40000, 233,0 }, - {1204,1204, 0, 0, 40000, 100,0 }, - {1205,1206, 0, 1, 40000, 266,0.03125 }, - {1207,1208, 0, 1, 40000, 260,-2.5e-05 }, - {1209,1209, 0, 0, 40000, 146,0 }, - {1210,1211, 0, 1, 40000, 60,0.03125 }, - {1212,1212, 0, 0, 40000, 53,0 }, - {1213,1214, 0, 1, 40000, 706,-0.09375 }, - {1215,1216, 0, 1, 40000, 660,-0.046875 }, - {1217,1217, 0, 0, 40000, 133,0 }, - {1218,1219, 0, 1, 40000, 426,0.03125 }, - {1220,1220, 0, 1, 40000, 0,0.03125 }, - {1221,1222, 0, 1, 40000, 260,0.171875 }, - {1223,1223, 0, 0, 40000, 0,0 }, - {1224,1224, 0, 0, 6100, 1580,0 }, - {1225,1150, 0, 1, 40000, 73,-0.03125 }, - {1226,1226, 0, 0, 40000, 1580,0 }, - {1227,1227, 0, 0, 40000, 40,0 }, - {1228,1229, 0, 1, 40000, 113,0.125 }, - {1230,1230, 0, 0, 2666, 846,0 }, - {1231,1232, 0, 1, 40000, 0,-0.03125 }, - {1233,1234, 0, 1, 9233, 2413,-0.1875 }, - {1235,1235, 0, 0, 40000, 1020,0 }, - {1236,1236, 0, 0, 40000, 0,0 }, - {1237,1237, 0, 0, 9633, 3073,0 }, - {1238,1238, 0, 0, 40000, 0,0 }, - {1239,1239, 0, 0, 2446, 386,0 }, - {1240,1241, 0, 1, 3113, 1133,0 }, - {1242,1242, 0, 0, 18473, 813,0 }, - {1243,1243, 0, 0, 1206, 660,0 }, - {1244,1244, 0, 0, 40000, 153,0 }, - {1245,1245, 0, 0, 40000, 160,0 }, - {1246,1246, 0, 0, 40000, 133,0 }, - {1247,1247, 0, 0, 8660, 2386,0 }, - {1248,1248, 0, 0, 293, 106,0 }, - {1249,1249, 0, 0, 40000, 433,0 }, - {1250,1250, 0, 0, 426, 80,0 }, - {1251,1251, 0, 0, 973, 360,0 }, - {1252,1252, 0, 0, 573, 153,0 }, - {1253,1253, 0, 0, 3746, 126,0 }, - {1254,1254, 0, 0, 2313, 73,0 }, - {1255,1255, 0, 0, 1473, 106,0 }, - {1256,1256, 0, 0, 1500, 320,0 }, - {1257,1257, 0, 0, 5280, 1593,0 }, - {1258,1258, 0, 0, 40000, 60,0 }, - {1259,1259, 0, 0, 40000, 146,0 }, - {1260,1260, 29, 0, 40000, 300,0 }, - {1261,1261, 65, 0, 40000, 2040,0 }, - {1262,1262, 0, 0, 626, 240,0 }, - {1263,1263, 25, 0, 626, 226,0 }, - {1264,1264, 83, 0, 180, 80,0 }, - {1265,1265, 32, 0, 260, 140,0 }, - {1266,1266, 60, 0, 40000, 0,0 }, - {1267,1267, 36, 0, 286, 40,0 }, - {1268,1268, 27, 0, 573, 80,0 }, - {1269,1269, 31, 0, 693, 106,0 }, - {1270,1270, 21, 0, 500, 146,0 }, - {1270,1270, 26, 0, 493, 140,0 }, - {1270,1270, 28, 0, 500, 146,0 }, - {1271,1271, 60, 0, 2420, 1080,0 }, - {1270,1270, 32, 0, 413, 126,0 }, - {1272,1272, 60, 0, 806, 300,0 }, - {1273,1273, 96, 0, 1146, 493,0 }, - {1274,1274, 72, 0, 1246, 586,0 }, - {1275,1275, 79, 0, 286, 106,0 }, - {1276,1276, 69, 0, 1193, 1046,0 }, - {1277,1277, 71, 0, 340, 93,0 }, - {1278,1278, 22, 0, 1880, 653,0 }, - {1279,1279, 55, 0, 246, 120,0 }, - {1279,1279, 48, 0, 286, 133,0 }, - {1280,1280, 0, 0, 40, 0,0 }, - {1281,1281, 49, 2, 40, 0,0 }, - {1282,1282, 73, 0, 166, 33,0 }, - {1282,1282, 68, 0, 166, 33,0 }, - {1282,1282, 61, 0, 200, 40,0 }, - {1283,1283, 0, 0, 40, 0,0 }, - {1284,1284, 0, 0, 40000, 100,0 }, - {1285,1285, 0, 0, 40000, 60,0 }, - {1286,1286, 0, 0, 40000, 0,0 }, - {1287,1287, 0, 0, 10460, 153,0 }, - {1288,1289, 0, 1, 40000, 0,0 }, - {1290,1290, 0, 0, 40000, 0,0 }, - {1291,1292, 36, 1, 353, 153,0 }, - {1293,1293, 69, 0, 1206, 1060,0 }, - {1294,1294, 0, 0, 40000, 0,0 }, - {1295,1295, 0, 0, 40000, 73,0 }, - {1296,1296, 0, 0, 40000, 0,0 }, - {1297,1297, 22, 0, 1880, 653,0 }, - {1298,1298, 0, 0, 40000, 73,0 }, - {1299,1299, 0, 0, 3913, 420,0 }, - {1300,1300, 0, 0, 9233, 240,0 }, - {1301,1301, 0, 0, 4660, 1573,0 }, - {1302,1302, 0, 0, 1166, 400,0 }, - {1303,1303, 0, 0, 40000, 126,0 }, - {1304,1304, 0, 0, 40000, 93,0 }, - {1305,1305, 0, 0, 40000, 93,0 }, - {1306,1306, 0, 0, 40000, 553,0 }, - {1307,1307, 0, 0, 40000, 660,0 }, - {1308,1308, 0, 0, 40000, 73,0 }, - {1309,1309, 0, 0, 40000, 146,0 }, - {1310,1310, 0, 0, 40000, 146,0 }, - {1311,1311, 0, 0, 4026, 100,0 }, - {1312,1312, 0, 0, 18226, 100,0 }, - {1313,1313, 0, 0, 40000, 0,0 }, - {1314,1314, 0, 0, 40000, 73,0 }, - {1315,1315, 0, 0, 40000, 140,0 }, - {1316,1316, 0, 0, 40000, 393,0 }, - {1317,1317, 0, 0, 40000, 406,0 }, - {1318,1318, 0, 0, 40000, 373,0 }, - {1319,1319, 0, 0, 40000, 0,0 }, - {1320,1320, 0, 0, 40000, 360,0 }, - {1321,1321, 0, 0, 1060, 380,0 }, - {1322,1322, 0, 0, 40000, 66,0 }, - {1323,1323, 0, 0, 40000, 66,0 }, - {1324,1324, 0, 0, 40000, 86,0 }, - {1325,1325, 0, 0, 40000, 73,0 }, - { 260, 260, 0, 0, 40000, 80,0 }, - {1326,1326, 0, 0, 40000, 80,0 }, - {1327,1327, 0, 0, 40000, 73,0 }, - {1328,1328, 0, 0, 40000, 73,0 }, - {1329,1329, 0, 0, 40000, 153,0 }, - {1330,1330, 0, 0, 40000, 153,0 }, - {1331,1331, 0, 0, 40000, 146,0 }, - {1332,1332, 0, 0, 40000, 146,0 }, - {1333,1333, 0, 0, 40000, 73,0 }, - {1334,1334, 0, 0, 40000, 153,0 }, - {1335,1335, 0, 0, 40000, 233,0 }, - {1336,1336, 0, 0, 40000, 400,0 }, - {1337,1337, 0, 0, 40000, 1373,0 }, - {1338,1338, 0, 0, 40000, 193,0 }, - {1339,1339, 0, 0, 40000, 1273,0 }, - {1340,1340, 0, 0, 40000, 186,0 }, - {1341,1341, 0, 0, 40000, 86,0 }, - {1342,1342, 0, 0, 7440, 2473,0 }, - {1343,1343, 0, 0, 40000, 160,0 }, - {1344,1344, 0, 0, 8966, 406,0 }, - {1345,1345, 0, 0, 40000, 1353,0 }, - {1346,1346, 0, 0, 14180, 4406,0 }, - { 378, 378, 84, 0, 1333, 460,0 }, - {1347,1347, 24, 0, 1893, 633,0 }, - {1348,1348, 44, 0, 206, 86,0 }, - {1349,1349, 40, 0, 586, 140,0 }, - {1350,1350, 60, 0, 1026, 320,0 }, - {1351,1351, 0, 0, 6560, 33,0 }, - {1352,1352, 0, 0, 7373, 2453,0 }, - {1353,1353, 0, 0, 4660, 1573,0 }, - {1354,1354, 0, 0, 40000, 346,0 }, - {1355,1355, 0, 0, 7126, 86,0 }, - {1356,1356, 0, 0, 40000, 213,0 }, - {1357,1357, 0, 0, 1180, 340,0 }, - {1358,1358, 0, 0, 3893, 1466,0 }, - {1359,1359, 0, 0, 2053, 1173,0 }, - {1360,1360, 0, 0, 40000, 200,0 }, - {1361,1361, 0, 0, 40000, 353,0 }, - {1362,1362, 0, 0, 40000, 273,0 }, - {1363,1363, 0, 0, 40000, 433,0 }, - {1364,1364, 0, 0, 1940, 426,0 }, - {1365,1365, 0, 0, 40000, 80,0 }, - {1366,1366, 0, 0, 40000, 106,0 }, - {1367,1367, 0, 0, 40000, 60,0 }, - {1368,1368, 0, 0, 40000, 140,0 }, - {1369,1369, 0, 0, 40000, 93,0 }, - {1370,1370, 0, 0, 40000, 73,0 }, - {1371,1371, 0, 0, 40000, 73,0 }, - {1372,1372, 0, 0, 40000, 93,0 }, - {1373,1373, 0, 0, 40000, 73,0 }, - {1374,1374, 0, 0, 40000, 80,0 }, - {1375,1375, 0, 0, 40000, 746,0 }, - {1376,1376, 0, 0, 2360, 813,0 }, - {1377,1377, 0, 0, 340, 146,0 }, - {1378,1378, 35, 0, 713, 273,0 }, - {1379,1379, 49, 0, 173, 93,0 }, - {1377,1377, 48, 0, 286, 126,0 }, - {1380,1380, 58, 0, 173, 100,0 }, - {1377,1377, 60, 0, 286, 133,0 }, - {1381,1381, 47, 0, 973, 360,0 }, - {1382,1382, 60, 0, 146, 86,0 }, - {1381,1381, 49, 0, 966, 333,0 }, - {1383,1383, 72, 0, 506, 206,0 }, - {1381,1381, 51, 0, 953, 340,0 }, - {1384,1384, 84, 0, 1340, 480,0 }, - {1381,1381, 54, 0, 986, 360,0 }, - {1381,1381, 57, 0, 980, 346,0 }, - {1385,1385, 72, 0, 1573, 440,0 }, - {1381,1381, 60, 0, 953, 340,0 }, - {1386,1386, 36, 0, 2673, 900,0 }, - {1387,1387, 93, 0, 233, 106,0 }, - {1388,1388, 72, 0, 966, 353,0 }, - {1389,1389, 84, 0, 1366, 473,0 }, - {1390,1390, 36, 0, 1326, 446,0 }, - {1391,1391, 64, 0, 220, 86,0 }, - {1392,1392, 68, 0, 126, 220,0 }, - {1393,1393, 0, 0, 4513, 640,0 }, - {1394,1394, 0, 0, 40000, 353,0 }, - {1395,1395, 0, 0, 40000, 73,0 }, - {1396,1396, 0, 0, 2040, 380,0 }, - {1397,1397, 0, 0, 40000, 240,0 }, - {1398,1398, 0, 0, 3246, 753,0 }, - {1399,1399, 0, 0, 40000, 66,0 }, - {1400,1400, 0, 0, 40000, 0,0 }, - {1401,1401, 0, 0, 40000, 0,0 }, - {1402,1402, 0, 0, 7720, 1260,0 }, - {1403,1403, 0, 0, 213, 6420,0 }, - {1404,1404, 0, 0, 40000, 66,0 }, - {1405,1405, 0, 0, 40000, 73,0 }, - {1406,1406, 0, 0, 40000, 93,0 }, - {1407,1407, 0, 0, 1606, 640,0 }, - {1408,1408, 0, 0, 15486, 1580,0 }, - {1409,1409, 0, 0, 40000, 353,0 }, - {1410,1410, 0, 0, 40000, 2066,0 }, - {1411,1411, 0, 0, 40000, 0,0 }, - {1412,1412, 0, 0, 15453, 73,0 }, - {1413,1413, 0, 0, 3726, 1240,0 }, - {1414,1414, 0, 0, 40000, 86,0 }, - {1415,1415, 0, 0, 40000, 200,0 }, - {1416,1416, 0, 0, 40000, 53,0 }, - {1417,1417, 0, 0, 40000, 73,0 }, - {1418,1418, 0, 0, 40000, 66,0 }, - {1419,1419, 0, 0, 40000, 26,0 }, - {1420,1420, 0, 0, 40000, 53,0 }, - {1421,1421, 0, 0, 40000, 40,0 }, - {1422,1422, 0, 0, 40000, 126,0 }, - {1423,1423, 0, 0, 40000, 0,0 }, - {1424,1424, 0, 0, 13653, 0,0 }, - {1425,1425, 0, 0, 12533, 1953,0 }, - {1426,1426, 0, 0, 973, 1280,0 }, - {1427,1427, 0, 0, 40000, 426,0 }, - {1428,1428, 0, 0, 40000, 53,0 }, - {1429,1429, 0, 0, 40000, 66,0 }, - {1430,1430, 0, 0, 526, 840,0 }, - {1431,1431, 0, 0, 286, 1293,0 }, - {1432,1432, 0, 0, 14726, 4920,0 }, - {1433,1433, 0, 0, 5233, 633,0 }, - {1434,1434, 0, 0, 13226, 2500,0 }, - { 740, 740, 0, 0, 513, 200,0 }, - {1435,1435, 0, 0, 40000, 5666,0 }, - { 739, 739, 48, 0, 213, 20,0 }, - { 500, 500, 55, 0, 100, 0,0 }, - { 740, 740, 60, 0, 226, 113,0 }, - { 500, 500, 41, 0, 106, 0,0 }, - {1436,1436, 84, 0, 160, 26,0 }, - {1437,1437, 84, 0, 386, 493,0 }, - { 500, 500, 48, 0, 100, 0,0 }, - {1438,1438, 15, 0, 340, 140,0 }, - { 752, 752, 49, 0, 173, 20,0 }, - {1438,1438, 16, 0, 346, 146,0 }, - {1438,1438, 12, 0, 340, 140,0 }, - { 740, 740, 55, 0, 220, 113,0 }, - { 752, 752, 18, 0, 206, 20,0 }, - { 752, 752, 15, 0, 200, 20,0 }, - { 752, 752, 17, 0, 206, 20,0 }, - {1439,1440, 0, 4, 40000, 0,0 }, - {1441,1442, 0, 4, 7360, 200,0 }, - {1443,1444, 0, 4, 11840, 320,0 }, - {1445,1446, 0, 4, 9920, 326,0 }, - {1447,1448, 0, 4, 10213, 0,0 }, - {1449,1450, 0, 4, 7440, 2486,0 }, - { 181,1451, 0, 4, 2360, 733,0 }, - {1452,1453, 0, 4, 9260, 240,0 }, - {1454,1455, 0, 4, 40000, 0,0 }, - {1456,1457, 0, 4, 660, 126,0 }, - {1458,1459, 0, 4, 40000, 66,0 }, - { 190,1460, 0, 4, 40000, 60,0 }, - { 192,1461, 0, 4, 40000, 73,0 }, - {1462,1463, 0, 4, 40000, 353,0 }, - {1464,1465, 0, 4, 40000, 353,0 }, - {1466,1467, 0, 4, 40000, 66,0 }, - {1468,1469, 0, 4, 40000, 46,0 }, - { 35,1470, 0, 4, 40000, 46,0 }, - { 36,1471, 0, 4, 320, 0,0 }, - {1472,1473, 0, 4, 320, 0,0 }, - {1474,1475, 0, 4, 7986, 93,0 }, - { 39,1476, 0, 4, 1053, 226,0 }, - {1477,1476, 0, 4, 1060, 226,0 }, - {1478,1479, 0, 4, 40000, 453,0 }, - { 50,1480, 0, 4, 40000, 400,0 }, - {1481,1482, 0, 4, 40000, 133,0 }, - {1483,1484, 0, 4, 40000, 0,0 }, - {1485,1486, 0, 4, 40000, 226,0 }, - { 55,1487, 0, 4, 40000, 100,0 }, - {1488,1489, 0, 4, 40000, 93,0 }, - {1490,1491, 0, 4, 40000, 73,0 }, - {1492,1493, 0, 4, 40000, 73,0 }, - {1494,1495, 0, 4, 40000, 73,0 }, - {1496,1497, 0, 4, 40000, 80,0 }, - {1496,1498, 0, 4, 40000, 73,0 }, - {1499,1500, 0, 4, 40000, 66,0 }, - {1501,1502, 0, 4, 40000, 146,0 }, - {1503,1504, 0, 4, 40000, 93,0 }, - {1505,1506, 0, 4, 40000, 73,0 }, - { 86,1507, 0, 4, 40000, 80,0 }, - {1508,1509, 0, 4, 40000, 0,0 }, - {1510,1511, 0, 4, 40000, 60,0 }, - {1512,1513, 0, 4, 40000, 0,0 }, - {1514,1515, 0, 4, 40000, 0,0 }, - {1516,1517, 0, 4, 40000, 773,0 }, - {1518,1519, 0, 4, 5346, 2973,0 }, - {1520,1521, 0, 4, 40000, 406,0 }, - {1522,1523, 0, 4, 9080, 360,0 }, - {1524,1525, 0, 4, 40000, 1200,0 }, - {1526,1527, 0, 4, 40000, 800,0 }, - {1528,1529, 0, 4, 40000, 960,0 }, - { 111,1530, 0, 4, 1200, 433,0 }, - {1531,1532, 0, 4, 226, 386,0 }, - { 115,1533, 0, 4, 2433, 0,0 }, - {1534,1535, 0, 4, 1873, 646,0 }, - {1536,1537, 0, 4, 3013, 53,0 }, - {1538,1539, 0, 4, 1560, 720,0 }, - {1540, 339, 0, 6, 6, 0,0 }, - {1541, 339, 0, 6, 6, 0,0 }, - {1542,1543, 0, 4, 993, 93,0 }, - {1544,1545, 0, 4, 293, 86,0 }, - {1546,1547, 0, 4, 40000, 153,0 }, - { 364, 365, 44, 4, 120, 0,0 }, - { 129,1548, 48, 4, 173, 0,0 }, - { 367, 368, 58, 4, 173, 0,0 }, - { 129,1549, 60, 4, 173, 0,0 }, - {1550,1551, 48, 4, 520, 200,0 }, - { 132,1552, 43, 4, 173, 0,0 }, - {1550,1551, 49, 4, 520, 200,0 }, - {1553,1554, 43, 4, 160, 80,0 }, - {1550,1551, 51, 4, 513, 0,0 }, - { 134,1555, 43, 4, 1733, 0,0 }, - {1550,1551, 54, 4, 506, 0,0 }, - {1550,1551, 57, 4, 506, 0,0 }, - { 380, 381, 72, 4, 1580, 0,0 }, - {1550,1551, 60, 4, 520, 0,0 }, - {1556,1557, 70, 4, 826, 306,0 }, - { 374, 375, 60, 4, 973, 0,0 }, - {1558,1559, 36, 4, 1233, 0,0 }, - {1560,1561, 65, 4, 293, 133,0 }, - {1562,1563, 84, 4, 1360, 0,0 }, - {1564,1565, 59, 4, 380, 0,0 }, - {1566,1567, 84, 4, 1593, 566,0 }, - {1568,1569, 35, 4, 1353, 473,0 }, - {1570,1571, 44, 4, 413, 0,0 }, - {1572,1573, 67, 4, 246, 0,0 }, - {1574,1575, 66, 4, 293, 0,0 }, - { 145,1576, 59, 4, 146, 0,0 }, - {1577,1578, 51, 4, 360, 0,0 }, - {1579,1580, 45, 4, 246, 0,0 }, - {1581,1582, 71, 4, 433, 0,0 }, - { 149,1583, 60, 4, 280, 0,0 }, - {1584,1585, 58, 4, 173, 0,0 }, - {1586,1587, 53, 4, 173, 0,0 }, - { 397,1588, 64, 4, 220, 80,0 }, - {1589,1590, 71, 4, 106, 53,0 }, - {1591,1592, 61, 4, 1000, 340,0 }, - {1593,1594, 61, 4, 1000, 340,0 }, - { 391, 392, 48, 4, 160, 46,0 }, - { 391, 393, 48, 4, 380, 60,0 }, - {1595,1596, 69, 4, 120, 0,0 }, - { 159,1597, 68, 4, 120, 0,0 }, - { 159,1597, 63, 4, 140, 0,0 }, - {1598,1599, 74, 4, 893, 273,0 }, - {1600,1601, 60, 4, 1013, 306,0 }, - {1602,1603, 80, 4, 220, 0,0 }, - {1604,1605, 64, 4, 1366, 0,0 }, - {1606,1607, 69, 4, 120, 73,0 }, - { 398, 399, 55, 4, 1540, 193,0 }, - {1608,1609, 75, 4, 1573, 0,0 }, - {1610,1611, 68, 4, 120, 0,0 }, - {1612,1613, 48, 4, 360, 0,0 }, - {1614,1615, 53, 4, 606, 0,0 }, - {1616,1616, 0, 0, 40000, 1586,0 }, - {1617,1617, 0, 0, 40000, 1226,0 }, - {1618,1618, 0, 0, 4546, 766,0 }, - {1619,1619, 0, 0, 40000, 420,0 }, - {1620,1620, 0, 0, 40000, 1573,0 }, - {1621,1621, 0, 0, 3326, 806,0 }, - {1622,1622, 0, 0, 40000, 746,0 }, - {1623,1623, 0, 0, 40000, 900,0 }, - {1624,1624, 0, 0, 12166, 1573,0 }, - {1625,1625, 0, 0, 40000, 80,0 }, - {1626,1626, 0, 0, 40000, 80,0 }, - {1627,1627, 0, 0, 40000, 80,0 }, - {1628,1628, 0, 0, 40000, 2713,0 }, - {1629,1629, 0, 0, 40000, 86,0 }, - {1630,1630, 0, 0, 40000, 80,0 }, - {1631,1631, 0, 0, 40000, 80,0 }, - {1632,1632, 0, 0, 40000, 813,0 }, - {1633,1633, 0, 0, 40000, 80,0 }, - {1634,1634, 0, 0, 40000, 80,0 }, - {1635,1635, 0, 0, 40000, 80,0 }, - {1636,1636, 0, 0, 40000, 193,0 }, - {1637,1637, 0, 0, 2920, 733,0 }, - {1638,1638, 0, 0, 40000, 373,0 }, - {1639,1639, 0, 0, 2286, 226,0 }, - {1640,1640, 0, 0, 40000, 226,0 }, - {1641,1641, 0, 0, 40000, 226,0 }, - {1642,1642, 0, 0, 40000, 433,0 }, - {1643,1643, 0, 0, 40000, 813,0 }, - {1644,1644, 0, 0, 40000, 80,0 }, - {1645,1645, 0, 0, 40000, 80,0 }, - {1646,1646, 0, 0, 40000, 80,0 }, - {1647,1647, 0, 0, 40000, 80,0 }, - {1648,1648, 0, 0, 40000, 80,0 }, - {1649,1649, 0, 0, 40000, 80,0 }, - {1650,1650, 0, 0, 40000, 146,0 }, - {1651,1651, 0, 0, 40000, 1280,0 }, - {1652,1652, 0, 0, 40000, 513,0 }, - {1653,1653, 0, 0, 40000, 313,0 }, - {1654,1654, 0, 0, 40000, 773,0 }, - {1655,1655, 0, 0, 7400, 2480,0 }, - {1656,1656, 0, 0, 3760, 1253,0 }, - {1657,1657, 0, 0, 40000, 380,0 }, - {1658,1658, 0, 0, 40000, 333,0 }, - {1659,1659, 0, 0, 40000, 2926,0 }, - {1660,1660, 0, 0, 40000, 5666,0 }, - {1661,1661, 0, 0, 40000, 1613,0 }, - {1662,1662, 0, 0, 3746, 1273,0 }, - {1663,1663, 0, 0, 13653, 0,0 }, - {1664,1664, 0, 0, 4640, 1553,0 }, - {1665,1665, 0, 0, 40000, 680,0 }, - {1666,1666, 0, 0, 6393, 426,0 }, - {1667,1667, 0, 0, 40000, 713,0 }, - {1668,1668, 12, 0, 166, 20,0 }, - {1669,1669, 48, 0, 460, 193,0 }, - { 736, 736, 52, 0, 286, 20,0 }, - {1670,1670, 48, 0, 506, 200,0 }, - {1670,1670, 36, 0, 713, 260,0 }, - { 377, 377, 84, 0, 386, 493,0 }, - { 730, 730, 95, 0, 1886, 653,0 }, - {1669,1669, 84, 0, 386, 166,0 }, - { 755, 755, 20, 0, 633, 240,0 }, - { 755, 755, 22, 0, 626, 240,0 }, - { 755, 755, 24, 0, 633, 246,0 }, - {1671,1671, 0, 0, 2233, 220,0 }, - {1672,1672, 0, 0, 2233, 240,0 }, - {1673,1673, 0, 0, 2233, 206,0 }, - {1674,1674, 0, 0, 2126, 173,0 }, - {1675,1675, 0, 0, 7473, 73,0 }, - {1676,1676, 0, 0, 40000, 0,0 }, - {1677,1677, 0, 0, 3493, 193,0 }, - {1678,1678, 0, 0, 1746, 73,0 }, - {1679,1679, 0, 0, 1013, 400,0 }, - {1680,1680, 0, 0, 3473, 1560,0 }, - {1681,1681, 0, 0, 1073, 40,0 }, - {1682,1682, 0, 0, 40000, 380,0 }, - {1683,1683, 0, 0, 1166, 400,0 }, - {1684,1684, 0, 0, 606, 146,0 }, - {1685,1685, 0, 0, 4553, 1486,0 }, - {1686,1686, 0, 0, 1126, 80,0 }, - {1687,1687, 0, 0, 40000, 73,0 }, - {1688,1688, 0, 0, 40000, 60,0 }, - {1689,1689, 0, 0, 40000, 66,0 }, - {1690,1690, 0, 0, 40000, 73,0 }, - {1691,1691, 0, 0, 40000, 73,0 }, - {1692,1692, 0, 0, 40000, 73,0 }, - {1693,1693, 0, 0, 40000, 73,0 }, - {1694,1694, 0, 0, 6380, 53,0 }, - {1695,1695, 0, 0, 6380, 60,0 }, - {1696,1696, 0, 0, 40000, 53,0 }, - {1697,1697, 0, 0, 40000, 0,0 }, - {1698,1698, 0, 0, 1880, 80,0 }, - {1699,1699, 0, 0, 40000, 60,0 }, - {1700,1700, 0, 0, 40000, 60,0 }, - {1701,1701, 0, 0, 1460, 80,0 }, - {1702,1702, 0, 0, 40000, 73,0 }, - {1703,1703, 0, 0, 40000, 0,0 }, - {1704,1704, 0, 0, 40000, 146,0 }, - {1705,1705, 0, 0, 40000, 66,0 }, - {1706,1706, 0, 0, 40000, 73,0 }, - {1707,1707, 0, 0, 40000, 160,0 }, - {1708,1708, 0, 0, 40000, 73,0 }, - {1709,1709, 0, 0, 40000, 193,0 }, - {1710,1710, 0, 0, 3740, 1260,0 }, - {1711,1711, 0, 0, 40000, 180,0 }, - {1712,1712, 0, 0, 40000, 173,0 }, - {1713,1713, 0, 0, 40000, 113,0 }, - {1714,1714, 0, 0, 40000, 86,0 }, - {1715,1715, 0, 0, 1853, 633,0 }, - {1716,1716, 0, 0, 40000, 0,0 }, - {1717,1717, 0, 0, 1066, 306,0 }, - {1718,1718, 0, 0, 40000, 86,0 }, - {1719,1719, 0, 0, 40000, 586,0 }, - {1720,1720, 0, 0, 40000, 86,0 }, - {1721,1721, 0, 0, 40000, 93,0 }, - {1722,1722, 0, 0, 40000, 373,0 }, - {1723,1723, 0, 0, 40000, 113,0 }, - {1724,1724, 0, 0, 40000, 353,0 }, - {1725,1725, 0, 0, 420, 73,0 }, - {1726,1726, 0, 0, 40000, 66,0 }, - {1727,1727, 0, 0, 40000, 53,0 }, - {1728,1728, 0, 0, 40000, 66,0 }, - {1729,1729, 0, 0, 40000, 100,0 }, - {1730,1730, 0, 0, 40000, 93,0 }, - {1731,1731, 0, 0, 40000, 0,0 }, - {1732,1732, 0, 0, 40000, 73,0 }, - {1733,1733, 0, 0, 40000, 80,0 }, - {1734,1734, 0, 0, 40000, 80,0 }, - {1735,1735, 0, 0, 40000, 80,0 }, - {1736,1736, 0, 0, 40000, 80,0 }, - {1737,1737, 0, 0, 40000, 80,0 }, - {1738,1738, 0, 0, 40000, 73,0 }, - {1739,1739, 0, 0, 40000, 73,0 }, - {1740,1740, 0, 0, 40000, 106,0 }, - {1741,1741, 0, 0, 40000, 73,0 }, - {1742,1742, 0, 0, 40000, 73,0 }, - {1743,1743, 0, 0, 40000, 80,0 }, - {1744,1744, 0, 0, 40000, 0,0 }, - {1745,1745, 0, 0, 40000, 80,0 }, - {1746,1746, 0, 0, 40000, 66,0 }, - {1747,1747, 0, 0, 40000, 73,0 }, - {1748,1748, 0, 0, 40000, 0,0 }, - {1749,1749, 0, 0, 40000, 80,0 }, - {1750,1750, 0, 0, 40000, 66,0 }, - {1751,1751, 0, 0, 40000, 73,0 }, - {1752,1752, 0, 0, 40000, 80,0 }, - {1753,1753, 0, 0, 40000, 33,0 }, - {1754,1754, 0, 0, 40000, 0,0 }, - {1755,1755, 0, 0, 40000, 266,0 }, - {1756,1756, 0, 0, 40000, 160,0 }, - {1757,1757, 0, 0, 40000, 93,0 }, - {1758,1758, 0, 0, 40000, 660,0 }, - {1759,1759, 0, 0, 40000, 1453,0 }, - {1760,1760, 0, 0, 40000, 660,0 }, - {1761,1761, 0, 0, 40000, 120,0 }, - {1762,1762, 0, 0, 40000, 140,0 }, - {1763,1763, 0, 0, 9820, 393,0 }, - {1764,1764, 0, 0, 40000, 73,0 }, - {1765,1765, 0, 0, 3620, 1166,0 }, - {1766,1766, 0, 0, 40000, 0,0 }, - {1767,1767, 0, 0, 40000, 0,0 }, - {1768,1768, 0, 0, 40000, 813,0 }, - {1769,1769, 0, 0, 40000, 0,0 }, - {1770,1770, 0, 0, 40000, 2386,0 }, - {1771,1771, 0, 0, 4380, 400,0 }, - {1772,1772, 0, 0, 853, 0,0 }, - {1773,1773, 0, 0, 3700, 93,0 }, - {1774,1774, 0, 0, 1580, 300,0 }, - {1775,1775, 0, 0, 453, 140,0 }, - {1776,1776, 0, 0, 40000, 66,0 }, - {1777,1777, 0, 0, 40000, 73,0 }, - {1778,1778, 0, 0, 40000, 206,0 }, - {1779,1779, 0, 0, 4646, 1560,0 }, - {1780,1780, 0, 0, 353, 146,0 }, - {1781,1781, 0, 0, 1300, 400,0 }, - {1782,1782, 0, 0, 4593, 1546,0 }, - {1783,1783, 0, 0, 613, 226,0 }, - {1784,1784, 0, 0, 626, 233,0 }, - {1785,1785, 0, 0, 3020, 66,0 }, - {1786,1786, 0, 0, 1093, 186,0 }, - {1787,1787, 0, 0, 6053, 1240,0 }, - {1788,1788, 0, 0, 633, 126,0 }, - {1789,1789, 0, 0, 40000, 66,0 }, - {1790,1790, 0, 0, 40000, 73,0 }, - {1791,1791, 0, 0, 40000, 1253,0 }, - {1792,1792, 0, 0, 626, 246,0 }, - {1793,1793, 48, 0, 293, 120,0 }, - {1794,1794, 48, 0, 100, 0,0 }, - {1795,1795, 60, 0, 240, 133,0 }, - {1796,1796, 60, 0, 160, 66,0 }, - {1797,1797, 70, 0, 140, 33,0 }, - {1798,1798, 51, 0, 526, 206,0 }, - {1799,1799, 60, 0, 173, 93,0 }, - {1798,1798, 54, 0, 520, 200,0 }, - {1800,1800, 60, 0, 153, 80,0 }, - {1798,1798, 56, 0, 520, 206,0 }, - {1801,1801, 60, 0, 673, 206,0 }, - {1798,1798, 61, 0, 506, 200,0 }, - {1798,1798, 63, 0, 513, 206,0 }, - {1802,1802, 48, 0, 673, 200,0 }, - {1798,1798, 68, 0, 440, 180,0 }, - {1803,1803, 60, 0, 1873, 653,0 }, - {1804,1804, 60, 0, 673, 200,0 }, - {1805,1805, 66, 0, 306, 120,0 }, - {1806,1806, 60, 0, 673, 200,0 }, - { 379, 379, 59, 0, 173, 93,0 }, - {1802,1802, 64, 0, 673, 206,0 }, - {1807,1807, 48, 0, 1006, 20,0 }, - {1808,1808, 56, 0, 120, 40,0 }, - {1809,1809, 53, 0, 286, 133,0 }, - {1810,1810, 65, 0, 106, 0,0 }, - {1811,1811, 49, 0, 293, 133,0 }, - {1811,1811, 43, 0, 293, 133,0 }, - { 386, 386, 65, 0, 1013, 673,0 }, - { 386, 386, 60, 0, 1000, 660,0 }, - {1812,1812, 70, 0, 260, 113,0 }, - {1812,1812, 65, 0, 306, 120,0 }, - {1813,1813, 60, 0, 246, 106,0 }, - {1814,1814, 60, 0, 193, 120,0 }, - {1815,1815, 56, 0, 206, 13,0 }, - {1816,1816, 53, 0, 433, 73,0 }, - {1817,1817, 60, 0, 220, 113,0 }, - {1818,1818, 48, 0, 300, 66,0 }, - {1819,1819, 69, 0, 126, 0,0 }, - { 328, 328, 67, 0, 140, 93,0 }, - { 328, 328, 62, 0, 153, 100,0 }, - {1820,1820, 65, 0, 433, 100,0 }, - {1821,1821, 60, 0, 426, 100,0 }, - {1822,1822, 63, 0, 113, 46,0 }, - {1823,1823, 63, 0, 1866, 653,0 }, - {1824,1824, 67, 0, 273, 60,0 }, - {1825,1825, 60, 0, 973, 360,0 }, - {1825,1825, 72, 0, 806, 273,0 }, - { 401, 401, 62, 0, 46, 0,0 }, - {1826,1826, 48, 0, 126, 66,0 }, - {1827,1827, 53, 0, 980, 353,0 }, - {1828,1828, 60, 0, 293, 133,0 }, - {1829,1829, 60, 0, 160, 20,0 }, - {1830,1830, 60, 0, 126, 86,0 }, - {1831,1831, 60, 0, 173, 93,0 }, - {1832,1832, 0, 0, 40000, 106,0 }, - {1833,1833, 0, 0, 3780, 73,0 }, - {1834,1834, 0, 0, 3820, 1666,0 }, - {1835,1835, 0, 0, 40000, 73,0 }, - {1836,1836, 0, 0, 40000, 333,0 }, - {1837,1837, 0, 0, 40000, 220,0 }, - {1838,1838, 0, 0, 40000, 0,0 }, - {1839,1839, 0, 0, 40000, 53,0 }, - {1840,1840, 0, 0, 40000, 60,0 }, - {1841,1841, 0, 0, 5913, 2306,0 }, - {1842,1842, 0, 0, 7713, 2466,0 }, - { 525, 525, 0, 0, 4660, 660,0 }, - {1843,1843, 0, 0, 40000, 313,0 }, - {1844,1844, 0, 0, 40000, 0,0 }, - {1845,1845, 0, 0, 40000, 0,0 }, - {1846,1846, 0, 0, 1246, 453,0 }, - {1847,1847, 0, 0, 9600, 1580,0 }, - {1848,1848, 0, 0, 40000, 106,0 }, - {1849,1849, 0, 0, 2040, 400,0 }, - {1850,1850, 0, 0, 40000, 73,0 }, - {1851,1851, 0, 0, 4220, 620,0 }, - {1852,1852, 0, 0, 40000, 0,0 }, - {1853,1853, 0, 0, 40000, 433,0 }, - {1854,1854, 0, 0, 40000, 66,0 }, - {1855,1855, 0, 0, 40000, 46,0 }, - {1856,1856, 0, 0, 40000, 240,0 }, - {1857,1857, 0, 0, 40000, 313,0 }, - {1858,1858, 0, 0, 40000, 26,0 }, - {1859,1859, 0, 0, 40000, 0,0 }, - {1860,1860, 0, 0, 40000, 73,0 }, - {1861,1861, 0, 0, 6940, 66,0 }, - {1862,1862, 0, 0, 40000, 0,0 }, - {1863,1863, 0, 0, 40000, 60,0 }, - {1864,1864, 0, 0, 8140, 1440,0 }, - {1865,1865, 0, 0, 40000, 0,0 }, - {1866,1866, 0, 0, 40000, 613,0 }, - {1867,1867, 0, 0, 40000, 0,0 }, - {1868,1868, 0, 0, 633, 233,0 }, - {1869,1869, 0, 0, 40000, 226,0 }, - {1870,1870, 0, 0, 2280, 746,0 }, - {1871,1871, 0, 0, 1940, 633,0 }, - {1872,1872, 0, 0, 4220, 620,0 }, - {1873,1873, 0, 0, 40000, 133,0 }, - {1874,1874, 41, 0, 380, 153,0 }, - {1875,1875, 70, 0, 106, 0,0 }, - {1876,1876, 60, 0, 380, 206,0 }, - {1877,1877, 80, 0, 100, 0,0 }, - {1878,1878, 84, 0, 120, 0,0 }, - {1879,1879, 72, 0, 500, 433,0 }, - {1880,1880, 84, 0, 860, 553,0 }, - { 128, 128, 70, 0, 106, 0,0 }, - { 132, 132, 60, 0, 146, 86,0 }, - {1881,1882, 0, 4, 40000, 260,0 }, - {1883,1883, 0, 0, 40000, 0,0 }, - {1884,1885, 0, 4, 40000, 73,0 }, - {1886,1887, 0, 4, 40000, 86,0 }, - {1888,1889, 0, 4, 40000, 73,0 }, - {1890,1890, 0, 0, 40000, 300,0 }, - {1891,1891, 0, 0, 40000, 693,0 }, - {1892,1892, 0, 0, 40000, 586,0 }, - {1893,1893, 0, 0, 40000, 286,0 }, - {1894,1894, 0, 0, 1620, 773,0 }, - {1895,1895, 0, 0, 40000, 0,0 }, - {1896,1896, 0, 0, 40000, 193,0 }, - {1897,1897, 0, 0, 1873, 820,0 }, - {1898,1898, 0, 0, 4520, 753,0 }, - {1899,1899, 0, 0, 40000, 0,0 }, - {1900,1900, 0, 0, 40000, 220,0 }, - {1901,1901, 0, 0, 40000, 133,0 }, - {1902,1902, 0, 0, 40000, 73,0 }, - {1903,1903, 0, 0, 40000, 0,0 }, - {1904,1904, 0, 0, 7326, 2420,0 }, - {1905,1905, 0, 0, 1186, 446,0 }, - {1906,1906, 0, 0, 40000, 553,0 }, - {1907,1907, 0, 0, 40000, 293,0 }, - {1908,1908, 0, 0, 40000, 586,0 }, - {1909,1909, 0, 0, 2326, 793,0 }, - { 501, 501, 0, 0, 480, 226,0 }, - {1910,1910, 0, 0, 40000, 93,0 }, - {1911,1911, 0, 0, 620, 226,0 }, - {1912,1912, 0, 0, 2373, 800,0 }, - {1913,1913, 0, 0, 40000, 4986,0 }, - {1914,1914, 0, 0, 626, 240,0 }, - { 511, 511, 0, 0, 2326, 800,0 }, - {1915,1915, 0, 0, 340, 146,0 }, - {1910,1910, 60, 0, 40000, 93,0 }, - { 511, 511, 72, 0, 1566, 546,0 }, - {1915,1915, 84, 0, 246, 120,0 }, - {1916,1916, 0, 0, 40000, 0,0 }, - {1917,1917, 0, 0, 2713, 666,0 }, - {1918,1918, 0, 0, 40000, 0,0 }, - {1919,1919, 0, 0, 40000, 46,0 }, - {1920,1920, 0, 0, 40000, 0,0 }, - {1921,1921, 0, 0, 40000, 53,0 }, - {1922,1922, 0, 0, 40000, 33,0 }, - {1923,1923, 0, 0, 2073, 193,0 }, - {1924,1924, 0, 0, 40000, 146,0 }, - {1925,1925, 0, 0, 40000, 100,0 }, - {1926,1926, 0, 0, 40000, 93,0 }, - {1927,1927, 0, 0, 40000, 73,0 }, - {1928,1928, 0, 0, 40000, 540,0 }, - {1929,1929, 0, 0, 40000, 520,0 }, - {1930,1930, 0, 0, 40000, 506,0 }, - {1931,1931, 0, 0, 7406, 200,0 }, - {1932,1932, 0, 0, 5906, 133,0 }, - {1933,1933, 0, 0, 7426, 240,0 }, - {1934,1934, 0, 0, 7426, 240,0 }, - {1935,1935, 0, 0, 40000, 66,0 }, - {1936,1936, 0, 0, 40000, 66,0 }, - {1937,1937, 0, 0, 40000, 53,0 }, - {1938,1938, 0, 0, 40000, 66,0 }, - {1939,1939, 0, 0, 40000, 66,0 }, - {1940,1940, 0, 0, 40000, 53,0 }, - {1941,1941, 0, 0, 40000, 2146,0 }, - {1942,1942, 0, 0, 40000, 1126,0 }, - {1943,1943, 0, 0, 40000, 1020,0 }, - {1944,1944, 0, 0, 40000, 433,0 }, - {1945,1945, 0, 0, 40000, 0,0 }, - {1946,1946, 0, 0, 40000, 140,0 }, - {1947,1947, 0, 0, 4660, 660,0 }, - {1948,1948, 0, 0, 40000, 66,0 }, - {1949,1949, 0, 0, 40000, 4193,0 }, - {1950,1950, 0, 0, 7713, 2466,0 }, - {1951,1951, 0, 0, 40000, 73,0 }, - {1952,1952, 0, 0, 8100, 2093,0 }, - {1953,1953, 0, 0, 40000, 86,0 }, - {1954,1954, 0, 0, 40000, 80,0 }, - {1955,1955, 0, 0, 4113, 1526,0 }, - {1956,1956, 0, 0, 40000, 66,0 }, - {1957,1957, 0, 0, 40000, 100,0 }, - {1958,1958, 0, 0, 40000, 213,0 }, - {1959,1959, 0, 0, 40000, 100,0 }, - {1960,1960, 0, 0, 1186, 100,0 }, - {1961,1961, 0, 0, 40000, 433,0 }, - {1962,1962, 0, 0, 40000, 146,0 }, - {1963,1963, 0, 0, 40000, 400,0 }, - {1964,1964, 0, 0, 40000, 66,0 }, - {1965,1965, 0, 0, 40000, 193,0 }, - {1966,1966, 0, 0, 1153, 100,0 }, - {1967,1967, 0, 0, 4800, 1400,0 }, - {1968,1968, 0, 0, 2906, 713,0 }, - {1969,1969, 0, 0, 40000, 73,0 }, - {1970,1970, 0, 0, 2280, 746,0 }, - {1971,1971, 0, 0, 40000, 66,0 }, - {1972,1972, 0, 0, 40000, 86,0 }, - {1973,1973, 0, 0, 40000, 86,0 }, - {1974,1974, 0, 0, 40000, 66,0 }, - {1975,1975, 0, 0, 40000, 66,0 }, - {1976,1976, 0, 0, 40000, 66,0 }, - {1977,1977, 0, 0, 40000, 46,0 }, - {1978,1978, 0, 0, 40000, 73,0 }, - {1979,1979, 0, 0, 40000, 73,0 }, - {1980,1980, 0, 0, 40000, 66,0 }, - {1981,1981, 0, 0, 40000, 66,0 }, - {1982,1982, 0, 0, 40000, 66,0 }, - {1983,1983, 0, 0, 40000, 73,0 }, - {1984,1984, 0, 0, 40000, 73,0 }, - {1985,1985, 0, 0, 40000, 253,0 }, - {1986,1986, 0, 0, 40000, 126,0 }, - {1987,1987, 0, 0, 40000, 126,0 }, - {1988,1988, 0, 0, 40000, 66,0 }, - {1989,1989, 0, 0, 40000, 66,0 }, - {1990,1990, 0, 0, 40000, 53,0 }, - {1991,1991, 0, 0, 40000, 140,0 }, - {1992,1992, 0, 0, 40000, 40,0 }, - {1993,1993, 0, 0, 40000, 73,0 }, - {1994,1994, 0, 0, 40000, 66,0 }, - {1995,1995, 0, 0, 40000, 73,0 }, - {1996,1996, 0, 0, 40000, 73,0 }, - {1997,1997, 0, 0, 40000, 73,0 }, - {1998,1998, 0, 0, 40000, 73,0 }, - {1999,1999, 0, 0, 40000, 66,0 }, - {2000,2000, 0, 0, 40000, 433,0 }, - {2001,2001, 0, 0, 40000, 433,0 }, - {2002,2002, 0, 0, 2440, 706,0 }, - {2003,2003, 0, 0, 13960, 4800,0 }, - {2004,2004, 0, 0, 7393, 2480,0 }, - {2005,2005, 0, 0, 7220, 2073,0 }, - {2006,2006, 0, 0, 633, 233,0 }, - {2007,2007, 0, 0, 2326, 780,0 }, - {2008,2008, 0, 0, 40000, 73,0 }, - {2009,2009, 0, 0, 40000, 106,0 }, - {2010,2010, 0, 0, 40000, 126,0 }, - {2011,2011, 0, 0, 40000, 386,0 }, - {2012,2012, 0, 0, 40000, 66,0 }, - {2013,2013, 0, 0, 6893, 1273,0 }, - {2014,2014, 0, 0, 2546, 633,0 }, - {2015,2015, 0, 0, 206, 106,0 }, - {2016,2016, 0, 0, 213, 113,0 }, - {2017,2017, 0, 0, 360, 140,0 }, - {2018,2018, 0, 0, 1013, 193,0 }, - {2019,2019, 0, 0, 266, 66,0 }, - {2020,2020, 0, 0, 1880, 660,0 }, - {2021,2021, 0, 0, 286, 206,0 }, - {2022,2022, 0, 0, 3706, 1353,0 }, - {2023,2023, 0, 0, 1106, 380,0 }, - {2024,2024, 0, 0, 13220, 2466,0 }, - {2025,2025, 0, 0, 333, 26,0 }, - {2026,2026, 0, 0, 7346, 2440,0 }, - {2027,2027, 0, 0, 1273, 453,0 }, - { 352, 352, 51, 2, 6, 0,0 }, - {2028,2028, 35, 0, 700, 253,0 }, - {2028,2028, 36, 0, 706, 266,0 }, - {2029,2029, 47, 0, 100, 0,0 }, - {2030,2030, 38, 0, 346, 140,0 }, - {2019,2019, 39, 0, 220, 106,0 }, - {2031,2031, 45, 0, 286, 133,0 }, - { 492, 492, 41, 0, 1040, 406,0 }, - {2032,2032, 42, 0, 220, 106,0 }, - {2033,2033, 44, 0, 500, 193,0 }, - { 492, 492, 48, 0, 833, 346,0 }, - {2034,2034, 46, 0, 1866, 646,0 }, - { 492, 492, 53, 0, 873, 386,0 }, - { 167, 167, 56, 0, 646, 353,0 }, - {2035,2035, 61, 0, 366, 146,0 }, - {2036,2036, 56, 0, 1346, 473,0 }, - {2037,2037, 60, 0, 213, 126,0 }, - { 144, 144, 59, 0, 213, 0,0 }, - {2038,2038, 59, 0, 106, 0,0 }, - { 169, 169, 51, 0, 380, 366,0 }, - { 169, 169, 45, 0, 380, 366,0 }, - {2039,2039, 72, 0, 246, 20,0 }, - {2040,2040, 60, 0, 280, 20,0 }, - {2041,2041, 58, 0, 373, 360,0 }, - {2042,2042, 53, 0, 380, 366,0 }, - {2043,2043, 73, 0, 120, 26,0 }, - { 158, 158, 75, 0, 126, 140,0 }, - {2044,2044, 0, 0, 6786, 1073,0 }, - {2045,2045, 0, 0, 2046, 473,0 }, - {2046,2046, 0, 0, 3746, 1273,0 }, - {2047,2047, 0, 0, 1200, 3086,0 }, - {2048,2048, 0, 0, 1200, 3080,0 }, - {2049,2049, 0, 0, 40000, 2453,0 }, - {2050,2050, 0, 0, 40000, 413,0 }, - {2051,2051, 0, 0, 980, 2553,0 }, - {2052,2052, 0, 0, 40000, 2420,0 }, - {2053,2053, 0, 0, 40000, 2506,0 }, - {2054,2054, 0, 0, 40000, 380,0 }, - {2055,2055, 0, 0, 40000, 660,0 }, - {2056,2056, 0, 0, 40000, 73,0 }, - {2057,2057, 0, 0, 40000, 333,0 }, - {2058,2058, 0, 0, 833, 146,0 }, - {2059,2059, 0, 0, 1686, 620,0 }, - {2060,2060, 0, 0, 40000, 73,0 }, - {2061,2061, 0, 0, 40000, 0,0 }, - {2062,2062, 0, 0, 1873, 633,0 }, - {2063,2063, 0, 0, 40000, 380,0 }, - {2064,2064, 0, 0, 366, 286,0 }, - {2065,2065, 0, 0, 8866, 1366,0 }, - {2066,2066, 0, 0, 40000, 1513,0 }, - {2067,2067, 0, 0, 40000, 333,0 }, - {2068,2068, 0, 0, 9600, 1573,0 }, - {2069,2069, 0, 0, 3293, 746,0 }, - {2070,2070, 0, 0, 40000, 53,0 }, - {2071,2071, 0, 0, 40000, 73,0 }, - {2072,2072, 0, 0, 40000, 73,0 }, - {2073,2073, 0, 0, 40000, 240,0 }, - {2074,2074, 0, 0, 40000, 240,0 }, - {2075,2075, 0, 0, 40000, 140,0 }, - {2076,2076, 0, 0, 40000, 113,0 }, - {2077,2077, 0, 0, 40000, 240,0 }, - {2078,2078, 0, 0, 3613, 1146,0 }, - {2079,2079, 0, 0, 40000, 126,0 }, - {2080,2080, 0, 0, 40000, 0,0 }, - {2081,2081, 0, 0, 40000, 633,0 }, - {2082,2082, 0, 0, 40000, 453,0 }, - {2083,2083, 0, 0, 40000, 1146,0 }, - {2084,2084, 0, 0, 40000, 3600,0 }, - {2085,2085, 0, 0, 40000, 1586,0 }, - {2086,2086, 0, 0, 40000, 1586,0 }, - {2087,2087, 0, 0, 40000, 1586,0 }, - {2088,2088, 0, 0, 40000, 1646,0 }, - {2089,2089, 0, 0, 40000, 1580,0 }, - {2090,2090, 0, 0, 40000, 4393,0 }, - {2091,2091, 0, 0, 40000, 4540,0 }, - {2092,2092, 0, 0, 21373, 6160,0 }, - {2093,2093, 0, 0, 40000, 633,0 }, - {2094,2094, 0, 0, 18420, 6146,0 }, - {2095,2095, 0, 0, 2306, 813,0 }, - {2096,2096, 0, 0, 2813, 333,0 }, - {2097,2097, 0, 0, 3106, 600,0 }, - {2098,2098, 0, 0, 1026, 1580,0 }, - {2099,2099, 0, 0, 1873, 346,0 }, - {2100,2100, 0, 0, 40000, 73,0 }, - {2101,2101, 0, 0, 40000, 73,0 }, - {2102,2102, 0, 0, 1200, 1906,0 }, - {2103,2103, 0, 0, 980, 1313,0 }, - {2104,2104, 0, 0, 200, 20,0 }, - {2105,2105, 0, 0, 640, 253,0 }, - {2106,2106, 0, 0, 3120, 240,0 }, - {2107,2107, 0, 0, 753, 146,0 }, - {2108,2108, 0, 0, 40000, 3060,0 }, - {2109,2109, 0, 0, 40000, 233,0 }, - {2110,2110, 0, 0, 40000, 246,0 }, - {2111,2111, 0, 0, 40000, 240,0 }, - { 752, 752, 60, 0, 173, 20,0 }, - { 755, 755, 12, 0, 626, 240,0 }, - {2112,2112, 89, 0, 113, 0,0 }, - {2113,2113, 89, 0, 700, 266,0 }, - { 755, 755, 14, 0, 626, 240,0 }, - { 755, 755, 16, 0, 626, 246,0 }, - {2114,2114, 84, 0, 1593, 553,0 }, - { 755, 755, 19, 0, 626, 240,0 }, - {2115,2115, 38, 0, 220, 166,0 }, - {2116,2116, 36, 0, 1686, 760,0 }, - { 755, 755, 28, 0, 626, 240,0 }, - { 755, 755, 26, 0, 626, 240,0 }, - { 755, 755, 35, 0, 633, 246,0 }, - { 755, 755, 30, 0, 626, 240,0 }, - {2117,2117, 60, 0, 180, 53,0 }, - {2104,2104, 60, 0, 173, 20,0 }, - {2104,2104, 55, 0, 173, 20,0 }, - { 730, 730, 94, 0, 1886, 660,0 }, - {2118,2118, 0, 0, 1226, 73,0 }, - {2119,2119, 0, 0, 40000, 0,0 }, - {2120,2120, 0, 0, 40000, 146,0 }, - {2121,2121, 0, 0, 40000, 80,0 }, - {2122,2122, 0, 0, 40000, 80,0 }, - {2123,2123, 0, 0, 40000, 0,0 }, - {2124,2124, 0, 0, 40000, 126,0 }, - {2125,2125, 0, 0, 40000, 213,0 }, - {2126,2126, 0, 0, 40000, 80,0 }, - {2127,2127, 0, 0, 40000, 73,0 }, - {2128,2128, 0, 0, 40000, 73,0 }, - {2129,2129, 0, 0, 40000, 73,0 }, - {2130,2130, 0, 0, 40000, 80,0 }, - {2131,2131, 0, 0, 40000, 73,0 }, - {2132,2132, 0, 0, 40000, 73,0 }, - {2133,2133, 0, 0, 40000, 66,0 }, - {2134,2134, 0, 0, 40000, 186,0 }, - {2135,2135, 0, 0, 9966, 426,0 }, - {2136,2136, 0, 0, 40000, 400,0 }, - {2137,2137, 0, 0, 40000, 326,0 }, - {2138,2138, 0, 0, 386, 80,0 }, - {2139,2139, 0, 0, 40000, 246,0 }, - {2140,2140, 0, 0, 3473, 73,0 }, - {2141,2141, 60, 0, 160, 66,0 }, - {2141,2141, 44, 0, 160, 60,0 }, - {2142,2142, 47, 0, 173, 93,0 }, - {2143,2143, 47, 0, 186, 80,0 }, - {2144,2144, 62, 0, 1933, 93,0 }, - {2145,2145, 93, 0, 1146, 473,0 }, - {2146,2146, 50, 0, 286, 93,0 }, - {2145,2145, 40, 0, 2013, 840,0 }, - {2147,2147, 60, 0, 106, 73,0 }, - { 898, 898, 60, 0, 173, 133,0 }, - {2147,2147, 57, 0, 106, 73,0 }, - { 900, 900, 42, 0, 620, 240,0 }, - { 900, 900, 38, 0, 626, 240,0 }, - { 908, 908, 88, 0, 160, 26,0 }, - {2148,2148, 0, 0, 9440, 140,0 }, - {2149,2149, 0, 0, 40000, 73,0 }, - {2150,2150, 0, 0, 4613, 420,0 }, - {2151,2151, 0, 0, 40000, 86,0 }, - {2152,2152, 0, 0, 40000, 406,0 }, - {2153,2153, 0, 0, 40000, 440,0 }, - {2154,2154, 0, 0, 4340, 133,0 }, - {2155,2155, 0, 0, 4460, 706,0 }, - {2156,2156, 0, 0, 40000, 73,0 }, - {2157,2157, 0, 0, 4660, 1573,0 }, - {2158,2158, 0, 0, 966, 333,0 }, - {2159,2159, 0, 0, 1933, 640,0 }, - { 136, 136, 0, 0, 2326, 786,0 }, - { 168, 168, 0, 0, 286, 366,0 }, - { 164, 164, 0, 0, 7373, 2460,0 }, - { 167, 167, 0, 0, 793, 426,0 }, - {2160,2160, 65, 0, 166, 73,0 }, - {2161,2161, 21, 0, 480, 146,0 }, - {2162, 173, 0, 4, 4220, 80,0 }, - {2163,2164, 0, 4, 4640, 3066,0 }, - {2165,2166, 0, 4, 7273, 3920,0 }, - {2167,2168, 0, 4, 3766, 1253,0 }, - {2169,2170, 0, 4, 6266, 2400,0 }, - {2171,2172, 0, 4, 18213, 0,0 }, - {2173,2174, 0, 4, 40000, 713,0 }, - {2175,2174, 0, 4, 40000, 733,0 }, - {2176, 299, 0, 4, 40000, 273,0 }, - {2177,2178, 0, 4, 40000, 66,0 }, - {2179,2180, 0, 4, 40000, 393,0 }, - {2181,2182, 0, 4, 40000, 413,0 }, - {2183,2184, 0, 4, 7406, 200,0 }, - { 127, 127, 65, 0, 226, 120,0 }, - { 127, 127, 72, 0, 180, 100,0 }, - { 364, 365, 52, 4, 120, 0,0 }, - {2185,2186, 60, 4, 173, 0,0 }, - {1550,1551, 47, 4, 520, 0,0 }, - {1556,1557, 76, 4, 833, 0,0 }, - { 374, 375, 84, 4, 813, 0,0 }, - {1564,1565, 83, 4, 220, 0,0 }, - {1568,1569, 24, 4, 1840, 620,0 }, - {1556,1557, 77, 4, 820, 300,0 }, - {1572,1573, 60, 4, 286, 0,0 }, - {1574,1575, 65, 4, 293, 0,0 }, - { 391, 392, 44, 4, 160, 53,0 }, - { 391, 393, 40, 4, 460, 66,0 }, - {1606,1607, 72, 4, 120, 73,0 }, - { 398, 399, 73, 4, 1293, 173,0 }, - {1608,1609, 70, 4, 1580, 0,0 }, - {2187,2187, 0, 0, 40000, 353,0 }, - {2188,2188, 0, 0, 40000, 333,0 }, - {2189,2189, 0, 0, 5913, 2306,0 }, - {2190,2190, 0, 0, 7720, 1260,0 }, - {2191,2191, 0, 0, 213, 6420,0 }, - {2192,2192, 0, 0, 40000, 380,0 }, - {2193,2193, 0, 0, 1153, 760,0 }, - {2194,2194, 0, 0, 40000, 66,0 }, - {2195,2195, 0, 0, 4440, 66,0 }, - {2196,2196, 0, 0, 40000, 73,0 }, - {2197,2197, 0, 0, 40000, 53,0 }, - {2198,2198, 0, 0, 40000, 60,0 }, - {2199,2199, 0, 0, 40000, 60,0 }, - {2200,2200, 0, 0, 8133, 1433,0 }, - { 528, 528, 0, 0, 966, 346,0 }, - {2201,2201, 0, 0, 40000, 126,0 }, - {2202,2202, 0, 0, 286, 1293,0 }, - {2203,2203, 0, 0, 40000, 0,0 }, - {2204,2204, 41, 0, 246, 20,0 }, - {2205,2205, 84, 0, 160, 26,0 }, - {2206,2206, 72, 0, 440, 180,0 }, - { 741, 741, 48, 0, 220, 26,0 }, - {2207,2207, 0, 0, 2126, 173,0 }, - {2208,2208, 0, 0, 40000, 0,0 }, - {2209,2209, 0, 0, 40000, 380,0 }, - {2210,2210, 0, 0, 4553, 1486,0 }, - {2211,2211, 0, 0, 40000, 73,0 }, - {2212,2212, 0, 0, 40000, 73,0 }, - {2213,2213, 0, 0, 1460, 80,0 }, - {2214,2214, 0, 0, 40000, 66,0 }, - {2215,2215, 0, 0, 40000, 186,0 }, - {2216,2216, 0, 0, 40000, 180,0 }, - {2217,2217, 0, 0, 40000, 173,0 }, - {2218,2218, 0, 0, 40000, 113,0 }, - {2219,2219, 0, 0, 40000, 86,0 }, - {2220,2220, 0, 0, 40000, 373,0 }, - {2221,2221, 0, 0, 40000, 113,0 }, - {2222,2222, 0, 0, 40000, 353,0 }, - {2223,2223, 0, 0, 40000, 66,0 }, - {2224,2224, 0, 0, 40000, 53,0 }, - {2225,2225, 0, 0, 40000, 66,0 }, - {2226,2226, 0, 0, 40000, 100,0 }, - {2227,2227, 0, 0, 40000, 73,0 }, - {2228,2228, 0, 0, 40000, 73,0 }, - {2229,2229, 0, 0, 40000, 66,0 }, - {2230,2230, 0, 0, 40000, 66,0 }, - {2231,2231, 0, 0, 40000, 80,0 }, - {2232,2232, 0, 0, 40000, 66,0 }, - {2233,2233, 0, 0, 40000, 80,0 }, - {2234,2234, 0, 0, 40000, 660,0 }, - {2235,2235, 0, 0, 40000, 120,0 }, - {2236,2236, 0, 0, 9820, 393,0 }, - {2237,2237, 0, 0, 40000, 73,0 }, - {2238,2238, 0, 0, 3620, 1166,0 }, - {2239,2239, 0, 0, 40000, 0,0 }, - {2240,2240, 0, 0, 40000, 0,0 }, - {2241,2241, 0, 0, 3020, 66,0 }, - {2242,2242, 0, 0, 6053, 1240,0 }, - {2243,2243, 0, 0, 633, 126,0 }, - {2244,2244, 0, 0, 40000, 66,0 }, - {2245,2245, 0, 0, 40000, 73,0 }, - {2246,2246, 0, 0, 626, 246,0 }, - {2247,2247, 60, 0, 173, 93,0 }, - {2248,2248, 60, 0, 673, 206,0 }, - {2249,2249, 48, 0, 673, 200,0 }, - {2250,2250, 60, 0, 1873, 653,0 }, - {2251,2251, 60, 0, 673, 200,0 }, - {2252,2252, 66, 0, 306, 120,0 }, - {2253,2253, 60, 0, 673, 200,0 }, - {2249,2249, 64, 0, 673, 206,0 }, - {2254,2254, 60, 0, 246, 106,0 }, - {2255,2255, 60, 0, 193, 120,0 }, - {2256,2256, 56, 0, 206, 13,0 }, - {2257,2257, 53, 0, 433, 73,0 }, - {2258,2258, 60, 0, 220, 113,0 }, - {2259,2259, 48, 0, 300, 66,0 }, - {2260,2260, 67, 0, 273, 60,0 }, - {2261,2261, 60, 0, 973, 360,0 }, - {2261,2261, 72, 0, 806, 273,0 }, - {2262,2262, 60, 0, 173, 93,0 }, - {2263,2263, 0, 0, 2493, 866,0 }, - {2264,2264, 24, 0, 173, 93,0 }, - {2265,2265, 36, 0, 140, 0,0 }, - { 343, 343, 36, 0, 146, 80,0 }, - { 347, 347, 0, 0, 353, 133,0 }, - { 347, 347, 12, 0, 420, 146,0 }, - {2266,2266, 12, 0, 346, 100,0 }, - {2267,2267, 24, 0, 106, 46,0 }, - {2267,2267, 36, 0, 100, 0,0 }, - {2268,2268, 0, 0, 1006, 293,0 }, - {2266,2266, 24, 0, 293, 93,0 }, - {2269,2269, 88, 0, 1106, 120,0 }, - {2270,2270, 88, 0, 666, 120,0 }, - {2271,2271, 13, 0, 760, 360,0 }, - { 351, 351, 0, 0, 966, 346,0 }, - {2271,2271, 15, 0, 760, 420,0 }, - {2272,2272, 0, 0, 4513, 640,0 }, - {2273,2273, 0, 0, 15486, 1580,0 }, - {2274,2274, 0, 0, 6940, 66,0 }, - {2275,2275, 0, 0, 6866, 2380,0 }, - {2276,2276, 0, 0, 7613, 1566,0 }, - {2277,2277, 0, 0, 1186, 420,0 }, - {2278,2278, 0, 0, 1166, 400,0 }, - {2279,2279, 0, 0, 40000, 2940,0 }, - {2280,2280, 0, 0, 40000, 0,0 }, - {2281,2281, 0, 0, 18226, 786,0 }, - {2282,2282, 0, 0, 40000, 0,0 }, - {2283,2283, 0, 0, 713, 200,0 }, - {2284,2284, 0, 0, 40000, 126,0 }, - {2285,2285, 0, 0, 40000, 353,0 }, - {2286,2286, 0, 0, 40000, 333,0 }, - {2287,2287, 0, 0, 40000, 0,0 }, - {2288,2288, 0, 0, 40000, 0,0 }, - {2289,2289, 0, 0, 40000, 0,0 }, - {2290,2290, 0, 0, 40000, 0,0 }, - {2291,2291, 0, 0, 40000, 73,0 }, - {2292,2292, 0, 0, 40000, 66,0 }, - {2293,2293, 0, 0, 15893, 153,0 }, - {2294,2294, 0, 0, 40000, 253,0 }, - {2295,2295, 0, 0, 2813, 333,0 }, - {2296,2296, 0, 0, 40000, 3920,0 }, - {2297,2297, 79, 0, 113, 0,0 }, - {2297,2297, 72, 0, 126, 140,0 }, - {2298,2298, 72, 0, 100, 26,0 }, - {2298,2298, 79, 0, 100, 0,0 }, - { 554, 554, 60, 0, 400, 126,0 }, - {2299,2299, 72, 0, 793, 173,0 }, - {2300,2300, 84, 0, 226, 66,0 }, - { 555, 555, 66, 0, 113, 0,0 }, - {2301,2302, 35, 4, 2333, 800,0 }, - {2303,2304, 52, 4, 120, 0,0 }, - {2305,1548, 48, 4, 173, 0,0 }, - {1595,1595, 58, 0, 146, 166,0 }, - {2305,1548, 60, 4, 173, 0,0 }, - {2306,2307, 47, 4, 1893, 700,0 }, - {2306,2307, 43, 4, 1953, 740,0 }, - {2306,2307, 49, 4, 1880, 686,0 }, - {2306,2307, 51, 4, 1886, 706,0 }, - {2306,2307, 54, 4, 1906, 720,0 }, - {2306,2307, 57, 4, 1900, 720,0 }, - {2306,2307, 72, 4, 1593, 606,0 }, - {2306,2307, 60, 4, 1900, 720,0 }, - {2306,2307, 76, 4, 1593, 606,0 }, - {2306,2307, 84, 4, 1593, 613,0 }, - {2306,2307, 36, 4, 2386, 920,0 }, - {1560,2308, 65, 4, 293, 213,0 }, - {2309,2310, 84, 4, 1373, 306,0 }, - {1564,1564, 83, 0, 220, 113,0 }, - { 380, 381, 84, 4, 1593, 566,0 }, - {1568,1568, 24, 0, 1833, 613,0 }, - {2306,2307, 77, 4, 1593, 606,0 }, - {2311,2312, 60, 4, 286, 0,0 }, - {2313,2314, 65, 4, 513, 0,0 }, - {2315,2315, 59, 0, 106, 0,0 }, - {2316,2316, 51, 0, 386, 373,0 }, - {1612,1612, 45, 0, 393, 380,0 }, - {2317,2317, 71, 0, 446, 180,0 }, - {2318,2318, 60, 0, 280, 20,0 }, - {2319,2319, 58, 0, 393, 373,0 }, - {2320,2320, 53, 0, 393, 380,0 }, - { 397, 397, 64, 0, 220, 86,0 }, - {2321,2321, 71, 0, 106, 46,0 }, - {2322,2322, 61, 0, 986, 340,0 }, - {2323,2323, 61, 0, 1893, 633,0 }, - {2324, 392, 44, 4, 166, 46,0 }, - {2324, 393, 40, 4, 460, 60,0 }, - {1595,1595, 69, 0, 126, 140,0 }, - {1595,1595, 68, 0, 126, 140,0 }, - {1595,1595, 63, 0, 146, 166,0 }, - {2325,2326, 74, 4, 380, 106,0 }, - {2327,2328, 60, 4, 1026, 333,0 }, - {2329,2330, 80, 4, 40000, 0,0 }, - {2331,2332, 64, 4, 1900, 640,0 }, - { 397, 397, 72, 0, 193, 80,0 }, - {2333,2334, 78, 4, 820, 0,0 }, - {1608,1609, 82, 4, 1580, 0,0 }, - {2315,2315, 48, 0, 106, 0,0 }, - {2316,2316, 53, 0, 386, 373,0 }, - {2335,2335, 0, 0, 3586, 1133,0 }, - {2336,2337, 0, 4, 1186, 420,0 }, - {2338,2339, 0, 4, 40000, 320,0 }, - {2340,2340, 0, 0, 8826, 1346,0 }, - {2341,2341, 0, 0, 3440, 753,0 }, - {2342,2342, 0, 0, 40000, 360,0 }, - {2343,2343, 0, 0, 40000, 413,0 }, - {2344,2345, 0, 4, 40000, 60,0 }, - {2346,2346, 0, 0, 40000, 60,0 }, - {2347,2348, 0, 4, 40000, 126,0 }, - {2349,2350, 0, 4, 40000, 73,0 }, - {2351,2352, 0, 4, 40000, 73,0 }, - {2353,2354, 0, 4, 40000, 86,0 }, - {2355,2356, 0, 4, 40000, 453,0 }, - {2357,2357, 14, 0, 186, 20,0 }, - {2358,2358, 35, 0, 246, 73,0 }, - {2357,2357, 19, 0, 166, 26,0 }, - {2359,2359, 43, 0, 286, 133,0 }, - {2360,2360, 41, 0, 300, 113,0 }, - {2360,2360, 43, 0, 253, 106,0 }, - {2360,2360, 45, 0, 240, 100,0 }, - {2360,2360, 47, 0, 240, 100,0 }, - {2361,2362, 0, 4, 14720, 333,0 }, - {2363,2363, 0, 0, 7373, 1246,0 }, - {2364,2364, 0, 0, 4900, 233,0 }, - {2365,2365, 0, 0, 5106, 606,0 }, - {2366,2366, 0, 0, 1333, 153,0 }, - {2367,2367, 0, 0, 2093, 840,0 }, - {2368,2368, 0, 0, 3700, 226,0 }, - {2369,2369, 0, 0, 3546, 0,0 }, - {2370,2370, 0, 0, 4606, 420,0 }, - {2371,2371, 0, 0, 14366, 606,0 }, - {2372,2372, 0, 0, 40000, 426,0 }, - {2373,2373, 0, 0, 3700, 200,0 }, - {2374,2374, 0, 0, 880, 440,0 }, - {2375,2375, 0, 0, 4660, 660,0 }, - {2376,2376, 0, 0, 3600, 1153,0 }, - {2377,2377, 0, 0, 40000, 73,0 }, - {2378,2378, 0, 0, 40000, 53,0 }, - {2379,2379, 0, 0, 40000, 333,0 }, - {2380,2380, 0, 0, 40000, 73,0 }, - {2381,2381, 0, 0, 40000, 73,0 }, - {2382,2382, 0, 0, 40000, 66,0 }, - {2383,2383, 0, 0, 40000, 73,0 }, - {2384,2384, 0, 0, 40000, 73,0 }, - {2385,2385, 0, 0, 840, 226,0 }, - {2386,2386, 0, 0, 2093, 86,0 }, - {2387,2387, 0, 0, 906, 73,0 }, - { 402, 402, 0, 0, 273, 60,0 }, - {2388,2388, 0, 0, 40000, 820,0 }, - {2389,2389, 0, 0, 4740, 93,0 }, - {2390,2390, 0, 0, 706, 106,0 }, - {2391,2391, 0, 0, 40000, 0,0 }, - {2392,2392, 0, 0, 3840, 2306,0 }, - {2393,2393, 0, 0, 3400, 493,0 }, - {2394,2394, 0, 0, 40000, 53,0 }, - {2395,2395, 0, 0, 40000, 133,0 }, - {2396,2397, 0, 4, 3093, 1400,0 }, - {2398,2398, 0, 0, 1080, 580,0 }, - {2399,2400, 0, 4, 2220, 400,0 }, - {2401,2401, 0, 0, 40000, 193,0 }, - {2402,2402, 0, 0, 40000, 60,0 }, - {2403,2404, 0, 4, 40000, 146,0 }, - {2405,2406, 0, 4, 40000, 133,0 }, - {2407,2408, 0, 4, 40000, 66,0 }, - {2409,2409, 0, 0, 40000, 0,0 }, - {2410,2410, 0, 0, 40000, 73,0 }, - {2411,2411, 0, 0, 40000, 66,0 }, - {2412,2413, 0, 4, 40000, 153,0 }, - {2414,2414, 0, 0, 40000, 126,0 }, - {2415,2416, 0, 4, 40000, 466,0 }, - {2417,2418, 0, 4, 40000, 113,0 }, - {2419,2420, 0, 4, 1280, 73,0 }, - {2421,2422, 0, 4, 1113, 146,0 }, - {2423,2424, 0, 4, 3660, 113,0 }, - {2425,2426, 0, 4, 40000, 80,0 }, - {2427,2427, 33, 0, 300, 246,0 }, - {2428,2429, 38, 4, 53, 0,0 }, - {2430,2430, 38, 0, 106, 0,0 }, - {2431,2431, 38, 0, 340, 20,0 }, - {2432,2432, 40, 0, 73, 0,0 }, - {2433,2434, 41, 4, 300, 0,0 }, - {2435,2435, 0, 0, 133, 73,0 }, - {2435,2435, 41, 0, 133, 73,0 }, - {2360,2360, 48, 0, 240, 100,0 }, - {2436,2436, 17, 0, 4620, 1553,0 }, - {2360,2360, 50, 0, 240, 100,0 }, - {2435,2435, 45, 0, 126, 66,0 }, - {2437,2437,254, 2, 6, 0,0 }, - {2438,2438, 60, 0, 226, 93,0 }, - {2439,2439, 56, 0, 233, 93,0 }, - {2440,2440, 60, 0, 140, 66,0 }, - {2440,2440, 55, 0, 140, 60,0 }, - {2441,2441, 63, 0, 286, 126,0 }, - {2442,2442, 57, 0, 173, 93,0 }, - {2443,2443, 0, 0, 40000, 280,0 }, - {2444,2444, 0, 0, 40000, 0,0 }, - {2445,2445, 0, 0, 40000, 746,0 }, - {2446,2446, 0, 0, 40000, 353,0 }, - {2447,2447, 0, 0, 40000, 1173,0 }, - {2448,2448, 0, 0, 40000, 146,0 }, - {2449,2449, 0, 0, 40000, 1160,0 }, - {2450,2450, 0, 0, 40000, 353,0 }, - {2451,2451, 0, 0, 18313, 6046,0 }, - {2452,2452, 0, 0, 1206, 420,0 }, - { 752, 752, 55, 0, 173, 20,0 }, - {2453,2453, 0, 0, 2860, 806,0 }, - {2454,2454, 0, 0, 2506, 126,0 }, - {2455,2455, 0, 0, 520, 93,0 }, - {2456,2456, 0, 0, 1420, 160,0 }, - {2457,2457, 0, 0, 40000, 53,0 }, - {2458,2458, 0, 0, 9106, 100,0 }, - {2459,2459, 0, 0, 3706, 100,0 }, - {2460,2460, 0, 0, 17933, 100,0 }, - {2461,2461, 0, 0, 40000, 0,0 }, - {2462,2462, 0, 0, 40000, 66,0 }, - {2463,2463, 0, 0, 40000, 0,0 }, - { 884, 884, 0, 0, 306, 73,0 }, - { 884, 884, 28, 0, 306, 73,0 }, - {2464,2464, 29, 0, 226, 93,0 }, - { 886, 886, 31, 0, 113, 0,0 }, - { 360, 360, 32, 0, 133, 40,0 }, - { 361, 361, 33, 0, 286, 80,0 }, - {2453,2453, 34, 0, 2873, 813,0 }, - { 888, 888, 29, 0, 246, 46,0 }, - { 886, 886, 55, 0, 100, 0,0 }, - { 890, 890, 48, 0, 240, 60,0 }, - { 884, 884, 58, 0, 146, 26,0 }, - {2465,2465, 45, 0, 173, 93,0 }, - {2465,2465, 43, 0, 173, 93,0 }, - {2466,2466, 73, 0, 1633, 86,0 }, - {2467,2467, 72, 0, 866, 553,0 }, - {2468,2468, 76, 0, 1380, 0,0 }, - {2467,2467, 84, 0, 873, 560,0 }, - {2468,2468, 36, 0, 1933, 880,0 }, - {2469,2469, 65, 0, 300, 120,0 }, - {2470,2470, 83, 0, 193, 86,0 }, - {2471,2471, 50, 0, 966, 126,0 }, - {2468,2468, 77, 0, 1373, 620,0 }, - { 897, 897, 55, 0, 126, 40,0 }, - {2472,2472, 60, 0, 180, 140,0 }, - { 897, 897, 50, 0, 126, 40,0 }, - {2473,2473, 42, 0, 633, 240,0 }, - {2473,2473, 46, 0, 513, 200,0 }, - {2474,2474, 71, 0, 433, 180,0 }, - {2474,2474, 60, 0, 513, 206,0 }, - {2455,2455, 58, 0, 220, 46,0 }, - {2455,2455, 53, 0, 286, 60,0 }, - {2475,2475, 91, 0, 186, 100,0 }, - {2476,2476, 61, 0, 226, 26,0 }, - {2477,2477, 61, 0, 886, 73,0 }, - {2478,2478, 44, 0, 120, 73,0 }, - {2479,2479, 40, 0, 933, 73,0 }, - {2480,2480, 69, 0, 146, 33,0 }, - { 361, 361, 68, 0, 153, 26,0 }, - { 361, 361, 63, 0, 180, 26,0 }, - {2481,2481, 74, 0, 153, 73,0 }, - {2482,2482, 60, 0, 280, 100,0 }, - { 908, 908, 80, 0, 160, 26,0 }, - {2483,2483, 64, 0, 986, 353,0 }, - {2483,2483, 73, 0, 813, 306,0 }, - {2483,2483, 70, 0, 820, 306,0 }, - { 886, 886, 68, 0, 93, 0,0 }, - { 886, 886, 48, 0, 106, 0,0 }, - {2484,2484, 0, 0, 40000, 0,0 }, - {2485,2485, 0, 0, 3226, 753,0 }, - {2486,2486, 0, 0, 1773, 553,0 }, - {2487,2487, 0, 0, 7473, 2460,0 }, - {2488,2488, 0, 0, 40000, 0,0 }, - {2489,2489, 0, 0, 40000, 353,0 }, - {2490,2490, 0, 0, 40000, 206,0 }, - {2491,2491, 0, 0, 40000, 86,0 }, - {2492,2492, 0, 0, 4740, 86,0 }, - {2493,2493, 0, 0, 6193, 193,0 }, - {2494,2494, 0, 0, 6200, 240,0 }, - {2495,2495, 0, 0, 40000, 0,0 }, - {2496,2496, 0, 0, 1586, 73,0 }, - {2497,2497, 0, 0, 560, 73,0 }, - {2498,2498, 0, 0, 40000, 480,0 }, - {2499,2499, 0, 0, 40000, 80,0 }, - {2500,2500, 0, 0, 40000, 66,0 }, - {2501,2501, 0, 0, 40000, 380,0 }, - {2502,2502, 0, 0, 280, 100,0 }, - {2503,2503, 0, 0, 6193, 233,0 }, - {2504,2504, 0, 0, 40000, 380,0 }, - {2505,2505, 0, 0, 40000, 0,0 }, - {2506,2506, 0, 0, 40000, 380,0 }, - {2507,2507, 0, 0, 40000, 200,0 }, - {2508,2508, 0, 0, 40000, 320,0 }, - {2509,2509, 0, 0, 40000, 126,0 }, - {2510,2510, 0, 0, 40000, 293,0 }, - {2511,2511, 0, 0, 40000, 0,0 }, - {2512,2512, 0, 0, 40000, 40,0 }, - {2513,2513, 0, 0, 40000, 106,0 }, - {2514,2514, 0, 0, 3846, 73,0 }, - {2515,2515, 0, 0, 40000, 0,0 }, - {2516,2516, 0, 0, 40000, 73,0 }, - {2517,2517, 0, 0, 40000, 533,0 }, - {2518,2518, 0, 0, 40000, 1020,0 }, - {2519,2519, 0, 0, 40000, 73,0 }, - {2520,2520, 0, 0, 40000, 53,0 }, - {2521,2521, 0, 0, 6153, 1433,0 }, - {2522,2522, 0, 0, 18813, 773,0 }, - {2523,2523, 0, 0, 40000, 433,0 }, - {2524,2524, 0, 0, 40000, 0,0 }, - {2525,2525, 0, 0, 40000, 133,0 }, - {2526,2526, 0, 0, 4486, 73,0 }, - { 346, 346, 30, 0, 540, 33,0 }, - { 346, 346, 31, 0, 406, 20,0 }, - { 346, 346, 32, 0, 406, 20,0 }, - { 346, 346, 33, 0, 406, 73,0 }, - { 346, 346, 34, 0, 406, 20,0 }, - { 346, 346, 35, 0, 406, 20,0 }, - { 346, 346, 37, 0, 406, 73,0 }, - { 346, 346, 39, 0, 406, 73,0 }, - { 346, 346, 41, 0, 406, 20,0 }, - { 346, 346, 43, 0, 306, 20,0 }, - { 346, 346, 45, 0, 306, 20,0 }, - { 346, 346, 47, 0, 306, 20,0 }, - { 346, 346, 48, 0, 306, 20,0 }, - { 346, 346, 49, 0, 306, 20,0 }, - { 512, 512, 84, 0, 353, 466,0 }, - {2206,2206, 84, 0, 440, 180,0 }, - {2527,2527, 55, 0, 100, 0,0 }, - {2528,2528, 36, 0, 400, 160,0 }, - {2529,2529, 38, 0, 313, 226,0 }, - {2530,2530, 60, 0, 286, 133,0 }, - {2531,2531, 38, 0, 200, 100,0 }, - {2532,2532, 17, 0, 6186, 240,0 }, - {2532,2532, 18, 0, 6186, 240,0 }, - {2532,2532, 19, 0, 6193, 233,0 }, - {2532,2532, 20, 0, 6193, 193,0 }, - {2532,2532, 21, 0, 6193, 193,0 }, - {2532,2532, 22, 0, 6193, 193,0 }, - {2532,2532, 23, 0, 6193, 193,0 }, - {2532,2532, 24, 0, 6193, 193,0 }, - {2532,2532, 25, 0, 6193, 193,0 }, - {2532,2532, 26, 0, 6193, 193,0 }, - {2532,2532, 27, 0, 6193, 253,0 }, - {2532,2532, 28, 0, 6193, 246,0 }, - {2532,2532, 29, 0, 6193, 246,0 }, - {2533,2533, 84, 0, 433, 180,0 }, - {2534,2534, 48, 0, 280, 93,0 }, - {2535,2535, 65, 0, 1166, 360,0 }, - {2536,2536, 65, 0, 1853, 633,0 }, - {2537,2537, 55, 0, 453, 366,0 }, - {2537,2537, 41, 0, 540, 433,0 }, - { 346, 346, 63, 0, 240, 66,0 }, - { 346, 346, 55, 0, 240, 66,0 }, - {2538,2538, 55, 0, 2586, 200,0 }, - {2538,2538, 53, 0, 2586, 200,0 }, - {2534,2534, 50, 0, 280, 93,0 }, - { 506, 506, 84, 0, 693, 566,0 }, - { 506, 506, 74, 0, 693, 560,0 }, - { 504, 504, 84, 0, 1566, 546,0 }, - { 504, 504, 74, 0, 1586, 560,0 }, - {2539,2539, 84, 0, 440, 20,0 }, - {2540,2540, 74, 0, 126, 26,0 }, - {1911,1911, 48, 0, 500, 180,0 }, - {1911,1911, 36, 0, 606, 220,0 }, - {2541,2541, 74, 0, 686, 560,0 }, - {2542,2542, 0, 0, 7313, 13,0 }, - {2543,2543, 0, 0, 40000, 1306,0 }, - {2544,2544, 0, 0, 40000, 0,0 }, - {2545,2545, 0, 0, 4613, 13,0 }, - {2546,2547, 0, 4, 6933, 133,0 }, - {2548,2549, 0, 4, 40000, 86,0 }, - {2550,2550, 0, 0, 9233, 100,0 }, - {2551,2552, 0, 4, 4640, 73,0 }, - {2553,2553, 0, 0, 40000, 73,0 }, - {2554,2554, 0, 0, 40000, 0,0 }, - {2555,2556, 0, 4, 40000, 73,0 }, - {2557,2557, 0, 0, 40000, 60,0 }, - {2558,1467, 0, 4, 40000, 66,0 }, - {2559,2560, 0, 4, 40000, 40,0 }, - {2561,2561, 0, 0, 40000, 186,0 }, - {2562,2562, 0, 0, 4026, 66,0 }, - {2563,2564, 0, 4, 14586, 80,0 }, - {2565,2565, 0, 0, 40000, 0,0 }, - {2566,2567, 0, 4, 40000, 40,0 }, - {2568,2568, 0, 0, 4020, 73,0 }, - {2569,2569, 0, 0, 40000, 0,0 }, - {2570,2570, 0, 0, 40000, 0,0 }, - {2571,2572, 0, 4, 40000, 126,0 }, - {2573,2574, 0, 4, 40000, 100,0 }, - {2575,2575, 0, 0, 40000, 213,0 }, - { 229,2576, 0, 4, 40000, 166,0 }, - {2577,2577, 0, 0, 7366, 53,0 }, - { 239,2578, 0, 4, 40000, 133,0 }, - {2579,2579, 0, 0, 40000, 80,0 }, - {2580,2580, 0, 0, 40000, 140,0 }, - {2581,2582, 0, 4, 16980, 1173,0 }, - {2583,2584, 0, 4, 726, 100,0 }, - {2585,2586, 0, 4, 40000, 73,0 }, - {2587,2588, 0, 4, 40000, 73,0 }, - {2589,2589, 0, 0, 40000, 60,0 }, - {2590,2590, 0, 0, 40000, 80,0 }, - {2591,2592, 0, 4, 40000, 73,0 }, - {2593,2594, 0, 4, 40000, 60,0 }, - {2595,2595, 0, 0, 40000, 66,0 }, - {2596,2597, 0, 4, 40000, 66,0 }, - {2598,2599, 0, 4, 40000, 60,0 }, - {2600,2601, 0, 4, 40000, 173,0 }, - {2602,2602, 0, 0, 40000, 60,0 }, - {2603,2603, 0, 0, 40000, 73,0 }, - {2604,2604, 0, 0, 40000, 93,0 }, - {2605,2606, 0, 4, 40000, 73,0 }, - {2607,2607, 0, 0, 40000, 66,0 }, - {2608,2609, 0, 4, 40000, 66,0 }, - {2610,2610, 0, 0, 40000, 86,0 }, - {2611,2611, 0, 0, 40000, 60,0 }, - {2612,2612, 0, 0, 14286, 73,0 }, - {2613,2613, 0, 0, 40000, 0,0 }, - {2614,2615, 0, 4, 40000, 73,0 }, - {2616,2617, 0, 4, 40000, 66,0 }, - {2618,2619, 0, 4, 133, 0,0 }, - {2620,2621, 0, 4, 40000, 1280,0 }, - {2622,2623, 0, 4, 40000, 160,0 }, - {2624,2625, 0, 4, 40000, 0,0 }, - {2626,2627, 0, 4, 40000, 73,0 }, - {2628,2629, 0, 4, 40000, 0,0 }, - {1516,2630, 0, 4, 1193, 406,0 }, - {2631,2632, 0, 4, 40000, 553,0 }, - {2633,2633, 0, 0, 40000, 40,0 }, - {2634,2635, 0, 4, 40000, 773,0 }, - {2636,2636, 0, 0, 40000, 320,0 }, - {2637,2637, 0, 0, 1880, 73,0 }, - {2638,2639, 0, 4, 486, 0,0 }, - {2640,2641, 0, 4, 17020, 1193,0 }, - {2642,2642, 0, 0, 40000, 720,0 }, - {2643,2644, 0, 4, 1880, 40,0 }, - {2645,2645, 0, 0, 40000, 73,0 }, - {2646,2647, 0, 4, 40000, 46,0 }, - {2648,2648, 0, 0, 2466, 80,0 }, - {2649,2649, 0, 0, 40000, 193,0 }, - {2650,2651, 0, 4, 993, 73,0 }, - {2652,2652, 0, 0, 40000, 220,0 }, - {2653,2654, 0, 4, 40000, 46,0 }, - {2655,2656, 0, 4, 40000, 46,0 }, - {2657,2657, 0, 0, 40000, 66,0 }, - {2658,2658, 35, 0, 626, 20,0 }, - {2659,2659, 35, 0, 306, 26,0 }, - {2660,2660, 52, 0, 126, 26,0 }, - {2661,2661, 60, 0, 286, 20,0 }, - {2662,2662, 58, 0, 113, 0,0 }, - {2663,2663, 60, 0, 380, 20,0 }, - {2664,2664, 50, 0, 1640, 66,0 }, - {2665,2665, 43, 0, 153, 20,0 }, - {2664,2664, 55, 0, 1640, 20,0 }, - {1553,1553, 43, 0, 160, 80,0 }, - {2666,2666, 50, 0, 980, 20,0 }, - {2667,2667, 43, 0, 446, 73,0 }, - {2666,2666, 53, 0, 1000, 80,0 }, - {2666,2666, 57, 0, 700, 73,0 }, - {2668,2668, 72, 0, 773, 13,0 }, - {2666,2666, 60, 0, 686, 20,0 }, - { 373, 373, 76, 0, 826, 20,0 }, - {2669,2669, 84, 0, 713, 20,0 }, - {2670,2670, 42, 0, 1186, 20,0 }, - {2671,2671, 65, 0, 293, 33,0 }, - {2672,2672, 84, 0, 386, 33,0 }, - {2673,2673, 84, 0, 1366, 20,0 }, - {2674,2674, 24, 0, 960, 73,0 }, - { 383, 383, 77, 0, 800, 20,0 }, - {2675,2675, 58, 0, 426, 26,0 }, - {2676,2676, 53, 0, 426, 20,0 }, - {2677,2677, 64, 0, 200, 66,0 }, - {2678,2678, 71, 0, 113, 13,0 }, - {2679,2679, 44, 0, 766, 66,0 }, - {2680,2680, 40, 0, 460, 60,0 }, - {2681,2681, 69, 0, 126, 26,0 }, - {2682,2682, 60, 0, 573, 66,0 }, - {2683,2683, 80, 0, 226, 20,0 }, - {2684,2684, 64, 0, 2693, 20,0 }, - {2685,2685, 72, 0, 120, 66,0 }, - {2686,2686, 70, 0, 820, 20,0 }, - {2687,2687, 48, 0, 173, 20,0 }, - {2688,2688, 53, 0, 980, 33,0 }, - {2689,2690, 0, 4, 40000, 286,0 }, - {2691,2692, 0, 4, 2340, 100,0 }, - {2693,2694, 0, 4, 380, 80,0 }, - {2695,2696, 0, 4, 14793, 73,0 }, - {2697,2698, 0, 4, 40000, 40,0 }, - { 192,2699, 0, 4, 40000, 73,0 }, - {2700,2701, 0, 4, 973, 126,0 }, - {2702,2703, 0, 4, 4666, 106,0 }, - {2704,2705, 0, 4, 40000, 73,0 }, - {2706,2707, 0, 4, 40000, 73,0 }, - {2708,2709, 0, 4, 40000, 73,0 }, - {2710,2711, 0, 4, 2053, 0,0 }, - {2712,1473, 0, 4, 320, 26,0 }, - {2713,2714, 0, 4, 573, 93,0 }, - {2715,2716, 0, 4, 6513, 0,0 }, - {1478,2717, 0, 4, 40000, 146,0 }, - {2718,2719, 0, 4, 40000, 66,0 }, - { 286,2720, 0, 4, 40000, 73,0 }, - {2721,2722, 0, 4, 40000, 86,0 }, - {2723,2724, 0, 4, 40000, 60,0 }, - {2725,2726, 0, 4, 393, 73,0 }, - {2727,2724, 0, 4, 40000, 60,0 }, - {1514,2728, 0, 4, 40000, 180,0 }, - {2729,2730, 0, 4, 40000, 0,0 }, - {2731,2732, 0, 4, 486, 0,0 }, - {2733,2734, 0, 4, 733, 0,0 }, - {2735,2736, 0, 4, 286, 40,0 }, - {2737,2738, 0, 4, 40000, 73,0 }, - {2739,2740, 0, 4, 1326, 746,0 }, - {2741,2742, 0, 4, 1340, 700,0 }, - {2743,2744, 0, 4, 40000, 0,0 }, - {2745,2746, 0, 4, 2046, 0,0 }, - {2747,2747, 35, 0, 386, 166,0 }, - {2748,2748, 60, 0, 493, 193,0 }, - {2749,2749, 43, 0, 126, 66,0 }, - {2750,2750, 0, 0, 3740, 1260,0 }, - {2751,2752, 0, 4, 14846, 353,0 }, - {2753,2754, 0, 4, 10266, 0,0 }, - {2755,2756, 0, 4, 18286, 146,0 }, - {2757,2758, 0, 4, 14520, 333,0 }, - {2759,2760, 0, 4, 14686, 633,0 }, - {2761,2762, 0, 4, 14826, 300,0 }, - {2763,2764, 0, 4, 10493, 0,0 }, - {2765,2766, 0, 4, 40000, 60,0 }, - {2767,2768, 0, 4, 40000, 80,0 }, - {2769,2770, 0, 4, 40000, 80,0 }, - {2771,2772, 0, 4, 40000, 73,0 }, - {2773,2774, 0, 4, 40000, 73,0 }, - {2775,2776, 0, 4, 40000, 80,0 }, - {2777,2778, 0, 4, 40000, 73,0 }, - {2779,2780, 0, 4, 40000, 73,0 }, - {2781,2782, 0, 4, 40000, 66,0 }, - {2783,2784, 0, 4, 7260, 186,0 }, - {2785,2786, 0, 4, 10386, 0,0 }, - {2787,2788, 0, 4, 40000, 246,0 }, - {2789,2790, 0, 4, 9173, 746,0 }, - {2791,2792, 0, 4, 7440, 666,0 }, - {2793,2794, 0, 4, 40000, 0,0 }, - {2795,2796, 0, 4, 40000, 413,0 }, - {2795,2797, 0, 4, 40000, 1506,0 }, - {2798,2799, 0, 4, 40000, 60,0 }, - {2800,2801, 0, 4, 40000, 233,0 }, - {2802,2803, 0, 4, 40000, 80,0 }, - {2804,2805, 0, 4, 40000, 80,0 }, - {2806,2807, 0, 4, 4520, 80,0 }, - {2808,2809, 0, 4, 40000, 73,0 }, - {2810,2811, 0, 4, 1186, 100,0 }, - {2812,2813, 0, 4, 953, 153,0 }, - {2814,2815, 0, 4, 14786, 126,0 }, - {2816,2817, 0, 4, 14800, 193,0 }, - {2818,2819, 0, 4, 14573, 626,0 }, - {2820,2821, 0, 4, 2200, 73,0 }, - {2822,2823, 0, 4, 373, 86,0 }, - {2824,2825, 0, 4, 12780, 200,0 }, - {2826,2827, 0, 4, 40000, 73,0 }, - {2828,2829, 0, 4, 9193, 146,0 }, - {2830,2831, 0, 4, 2540, 326,0 }, - {2832,2833, 0, 4, 6933, 200,0 }, - {2834,2835, 0, 4, 40000, 413,0 }, - {2836,2837, 0, 4, 4826, 1313,0 }, - {2838,2839, 0, 4, 14740, 340,0 }, - {2840,2841, 0, 4, 1886, 653,0 }, - {2842,2843, 0, 4, 5280, 260,0 }, - {2844,2845, 0, 4, 40000, 240,0 }, - {2846,2847, 0, 4, 40000, 240,0 }, - {2848,2849, 0, 4, 40000, 240,0 }, - {2850,2851, 0, 4, 40000, 406,0 }, - {2852,2853, 0, 4, 40000, 406,0 }, - {2854,2855, 0, 4, 40000, 146,0 }, - {2856,2856, 0, 0, 2400, 1126,0 }, - {2857,2857, 0, 0, 2400, 1126,0 }, - {2858,2859, 0, 4, 4613, 73,0 }, - {2860,2861, 0, 4, 40000, 426,0 }, - {2862,2863, 0, 4, 4580, 100,0 }, - {2864,2865, 0, 4, 40000, 80,0 }, - {2866,2867, 0, 4, 5300, 53,0 }, - {2868,2869, 0, 4, 5313, 113,0 }, - {2870,2871, 0, 4, 7080, 186,0 }, - {2872,2873, 0, 4, 4720, 106,0 }, - {2874,2875, 0, 4, 40000, 73,0 }, - {2876,2877, 0, 4, 1640, 0,0 }, - {2878,2879, 0, 4, 7306, 186,0 }, - {2880,2881, 0, 4, 7373, 1246,0 }, - {2882,2883, 0, 4, 4620, 93,0 }, - {2884,2885, 0, 4, 3460, 926,0 }, - {2886,2887, 0, 4, 40000, 73,0 }, - {2888,2888, 0, 0, 18926, 426,0 }, - {2889,2889, 0, 0, 18520, 73,0 }, - {2890,2890, 0, 0, 18473, 73,0 }, - {2891,2892, 0, 4, 40000, 93,0 }, - {2893,2893, 0, 0, 8006, 133,0 }, - {2894,2894, 0, 0, 18533, 66,0 }, - {2895,2895, 0, 0, 14786, 4966,0 }, - {2896,2897, 0, 4, 40000, 80,0 }, - {2898,2899, 0, 4, 40000, 73,0 }, - {2353,2900, 0, 4, 18520, 86,0 }, - {2901,2901, 0, 0, 40000, 0,0 }, - {2902,2903, 0, 4, 40000, 100,0 }, - {2904,2905, 0, 4, 40000, 93,0 }, - {2906,2907, 0, 4, 40000, 73,0 }, - {2908,2909, 0, 4, 10720, 153,0 }, - {2910,2911, 0, 4, 40000, 73,0 }, - {2912,2912, 0, 0, 40000, 40,0 }, - {2913,2914, 0, 4, 8720, 446,0 }, - {2915,2916, 0, 4, 14706, 653,0 }, - {2917,2918, 0, 4, 9213, 426,0 }, - {2919,2920, 0, 4, 9286, 240,0 }, - {2921,2922, 0, 4, 8706, 413,0 }, - {2923,2924, 0, 4, 2233, 346,0 }, - {2925,2926, 0, 4, 2373, 426,0 }, - {2927,2928, 0, 4, 2353, 233,0 }, - {2929,2929, 0, 0, 40000, 140,0 }, - {2930,2931, 0, 4, 40000, 100,0 }, - {2932,2933, 0, 4, 40000, 73,0 }, - {2934,2935, 0, 4, 40000, 80,0 }, - {2936,2937, 0, 4, 40000, 80,0 }, - {2938,2939, 0, 4, 40000, 246,0 }, - {2940,2940, 0, 0, 553, 446,0 }, - {2941,2941, 0, 0, 40000, 193,0 }, - {2942,2943, 0, 4, 1206, 406,0 }, - {2944,2944, 0, 0, 7026, 1553,0 }, - {2945,2945, 0, 0, 3426, 360,0 }, - {2946,2947, 0, 4, 7313, 646,0 }, - {2948,2948, 0, 0, 40000, 386,0 }, - {2949,2949, 0, 0, 1953, 726,0 }, - {2950,2951, 0, 4, 14606, 106,0 }, - {2952,2953, 0, 4, 40000, 1566,0 }, - {2954,2954, 60, 2, 6, 0,0 }, - {2955,2956, 0, 4, 40000, 240,0 }, - {2957,2958, 0, 4, 40000, 80,0 }, - {2959,2960, 0, 4, 40000, 113,0 }, - {2961,2962, 0, 4, 40000, 240,0 }, - {2963,2963, 0, 0, 8506, 680,0 }, - {2964,2964, 0, 0, 40000, 1593,0 }, - {2436,2436, 49, 0, 1873, 633,0 }, - {2357,2357, 61, 0, 113, 20,0 }, - {2357,2357, 56, 0, 113, 26,0 }, - {2357,2357, 58, 0, 113, 26,0 }, - {2357,2357, 49, 0, 126, 26,0 }, - {2357,2357, 44, 0, 126, 26,0 }, - {2965,2965, 0, 0, 40000, 380,0 }, - {2966,2966, 0, 0, 4440, 66,0 }, - {2967,2967, 0, 0, 8133, 1433,0 }, - {2968,2968, 0, 0, 40000, 126,0 }, - {2969,2969, 0, 0, 40000, 0,0 }, - {2970,2970, 84, 0, 160, 26,0 }, - {2971,2971, 72, 0, 440, 180,0 }, - {2972,2972, 0, 0, 8313, 580,0 }, - {2973,2973, 0, 0, 40000, 160,0 }, - {2974,2974, 0, 0, 40000, 3000,0 }, - {2975,2975, 0, 0, 8300, 493,0 }, - {2976,2976, 0, 0, 973, 673,0 }, - {2977,2977, 0, 0, 40000, 73,0 }, - {2978,2978, 0, 0, 40000, 133,0 }, - {2979,2979, 0, 0, 40000, 140,0 }, - {2980,2980, 0, 0, 40000, 346,0 }, - {2981,2981, 0, 0, 40000, 1006,0 }, - {2982,2982, 0, 0, 40000, 966,0 }, - {2983,2983, 0, 0, 40000, 0,0 }, - {2984,2984, 0, 0, 40000, 0,0 }, - {2985,2985, 0, 0, 40000, 66,0 }, - {2986,2986, 0, 0, 40000, 66,0 }, - {2987,2987, 0, 0, 40000, 46,0 }, - {2988,2988, 0, 0, 40000, 533,0 }, - {2989,2989, 0, 0, 2400, 780,0 }, - {2990,2990, 0, 0, 820, 66,0 }, - {2991,2991, 0, 0, 40000, 240,0 }, - {2992,2992, 0, 0, 40000, 220,0 }, - {2993,2993, 0, 0, 40000, 0,0 }, - {2994,2994, 0, 0, 15100, 73,0 }, - {2995,2995, 0, 0, 40000, 200,0 }, - {2996,2996, 0, 0, 2426, 93,0 }, - {2997,2997, 0, 0, 4640, 1553,0 }, - {2998,2998, 0, 0, 40000, 73,0 }, - {2999,2999, 0, 0, 40000, 73,0 }, - {3000,3000, 0, 0, 1133, 633,0 }, - {3001,3001, 0, 0, 40000, 0,0 }, - {3002,3002, 0, 0, 40000, 1006,0 }, - {3003,3003, 0, 0, 4653, 653,0 }, - {3004,3004, 0, 0, 40000, 1000,0 }, - {3005,3005, 0, 0, 40000, 53,0 }, - {3006,3006, 0, 0, 40000, 60,0 }, - {3007,3007, 0, 0, 40000, 0,0 }, - { 350, 350, 0, 0, 513, 200,0 }, - {3008,3008, 0, 0, 213, 106,0 }, - {3009,3009, 0, 0, 280, 126,0 }, - {3010,3010, 0, 0, 1193, 426,0 }, - {3011,3011, 0, 0, 14653, 4906,0 }, - {3012,3012, 0, 0, 1040, 326,0 }, - {3013,3013, 0, 0, 5740, 2326,0 }, - {3014,3014, 0, 0, 40000, 73,0 }, - {3015,3015, 0, 0, 40000, 240,0 }, - { 350, 350, 36, 0, 380, 153,0 }, - { 369, 369, 37, 0, 213, 66,0 }, - {3008,3008, 38, 0, 213, 106,0 }, - { 369, 369, 24, 0, 193, 13,0 }, - {3008,3008, 32, 0, 206, 106,0 }, - { 369, 369, 48, 0, 186, 20,0 }, - {3009,3009, 42, 0, 220, 106,0 }, - { 369, 369, 50, 0, 186, 73,0 }, - { 369, 369, 52, 0, 186, 73,0 }, - { 369, 369, 54, 0, 186, 33,0 }, - { 369, 369, 55, 0, 186, 33,0 }, - { 369, 369, 57, 0, 180, 33,0 }, - {3010,3010, 51, 0, 966, 353,0 }, - { 144, 144, 61, 0, 213, 126,0 }, - {3016,3016, 0, 0, 8340, 520,0 }, - {3016,3016, 63, 0, 6106, 373,0 }, - {3016,3016, 64, 0, 6073, 380,0 }, - {3017,3017, 40, 0, 206, 100,0 }, - {3017,3017, 70, 0, 160, 93,0 }, - {3018,3018, 0, 0, 40000, 73,0 }, - {3019,3019, 0, 0, 40000, 73,0 }, - {3020,3020, 0, 0, 40000, 73,0 }, - {3021,3021, 0, 0, 40000, 73,0 }, - {3022,3022, 38, 0, 246, 33,0 }, - {2441,2441, 57, 0, 286, 126,0 }, - {3023,3023, 63, 0, 146, 126,0 }, - {3024,3024, 74, 0, 280, 73,0 }, - {3025,3025, 74, 0, 453, 100,0 }, - {3026,3026, 60, 0, 666, 33,0 }, - {1439,1440, 0, 0, 13566, 273,0 }, - {1593,1594, 35, 0, 2200, 673,0 }, - {1564,1565, 35, 0, 740, 280,0 }, - {1443,1444, 0, 0, 11886, 333,0 }, - {1481,1482, 0, 0, 40000, 133,0 }, - { 185, 186, 0, 0, 5980, 1540,0 }, - { 235, 237, 0, 0, 3366, 1093,0 }, - { 239, 240, 0, 0, 40000, 133,0 }, - {1477,1476, 0, 0, 40000, 160,0 }, - { 268, 269, 0, 0, 40000, 80,0 }, - { 176, 177, 0, 0, 40000, 0,0 }, - {1490,1491, 0, 0, 40000, 60,0 }, - { 231, 232, 0, 0, 40000, 146,0 }, - { 233, 234, 0, 0, 40000, 433,0 }, - { 254, 255, 0, 0, 40000, 93,0 }, - { 192, 193, 0, 0, 40000, 66,0 }, - { 252, 253, 0, 0, 40000, 73,0 }, - { 248,3027, 0, 0, 40000, 80,0 }, - { 39,1476, 0, 0, 40000, 160,0 }, - { 241, 242, 0, 0, 40000, 146,0 }, - {1508,1509, 0, 0, 40000, 0,0 }, - { 246, 247, 0, 0, 3966, 800,0 }, - { 181,1451, 0, 0, 2153, 640,0 }, - { 209, 210, 0, 0, 4453, 100,0 }, - { 270, 271, 0, 0, 40000, 80,0 }, - { 115,1533, 0, 0, 4260, 1720,0 }, - {1454,1455, 0, 0, 40000, 0,0 }, - { 107, 319, 0, 0, 1266, 413,0 }, - { 46, 238, 0, 0, 6873, 1246,0 }, - { 216, 217, 0, 0, 4046, 100,0 }, - { 272, 273, 0, 0, 40000, 126,0 }, - {1445,3028, 0, 0, 9966, 386,0 }, - { 172, 173, 0, 0, 7340, 100,0 }, - { 174, 175, 0, 0, 6913, 100,0 }, - {1447,3029, 0, 0, 10306, 80,0 }, - {1452,3030, 0, 0, 9240, 240,0 }, - { 183, 184, 0, 0, 586, 253,0 }, - {1456,1457, 0, 0, 1386, 180,0 }, - {1458,1459, 0, 0, 40000, 60,0 }, - { 190,1460, 0, 0, 40000, 46,0 }, - {1462,1463, 0, 0, 40000, 340,0 }, - {1464,1465, 0, 0, 40000, 360,0 }, - { 195, 196, 0, 0, 40000, 66,0 }, - { 197, 198, 0, 0, 40000, 86,0 }, - { 199, 200, 0, 0, 40000, 60,0 }, - { 201, 202, 0, 0, 3713, 100,0 }, - { 203, 204, 0, 0, 14633, 126,0 }, - { 205, 206, 0, 0, 9440, 153,0 }, - { 214, 215, 0, 0, 17020, 100,0 }, - { 218, 219, 0, 0, 14000, 180,0 }, - { 220, 221, 0, 0, 2846, 100,0 }, - {1472,1473, 0, 0, 8066, 66,0 }, - {1474,1475, 0, 0, 8040, 93,0 }, - { 225, 226, 0, 0, 8066, 106,0 }, - { 229, 230, 0, 0, 40000, 160,0 }, - {1478,1479, 0, 0, 40000, 413,0 }, - { 50,1480, 0, 0, 40000, 393,0 }, - {1485,1486, 0, 0, 40000, 226,0 }, - { 258, 259, 0, 0, 40000, 73,0 }, - { 262, 263, 0, 0, 40000, 160,0 }, - { 264, 265, 0, 0, 40000, 160,0 }, - {1494,1495, 0, 0, 40000, 80,0 }, - {1496,1497, 0, 0, 40000, 73,0 }, - { 274, 275, 0, 0, 40000, 100,0 }, - {1499,1500, 0, 0, 40000, 73,0 }, - { 277, 278, 0, 0, 40000, 173,0 }, - { 279, 280, 0, 0, 40000, 160,0 }, - { 281, 282, 0, 0, 40000, 173,0 }, - {1501,1502, 0, 0, 40000, 146,0 }, - { 284, 285, 0, 0, 40000, 66,0 }, - { 286, 287, 0, 0, 40000, 86,0 }, - {1503,1504, 0, 0, 40000, 86,0 }, - {1505,1506, 0, 0, 40000, 73,0 }, - { 289, 290, 0, 0, 40000, 66,0 }, - { 291, 292, 0, 0, 40000, 160,0 }, - { 293, 294, 0, 0, 40000, 200,0 }, - { 86,1507, 0, 0, 40000, 80,0 }, - { 88, 297, 0, 0, 40000, 1346,0 }, - { 298, 299, 0, 0, 40000, 320,0 }, - { 300, 301, 0, 0, 40000, 1273,0 }, - {1514,1515, 0, 0, 40000, 100,0 }, - {1518,1519, 0, 0, 4733, 0,0 }, - {1520,1521, 0, 0, 40000, 440,0 }, - {1524,1525, 0, 0, 40000, 1180,0 }, - {1526,1527, 0, 0, 40000, 746,0 }, - {1528,1529, 0, 0, 40000, 920,0 }, - { 311, 312, 0, 0, 15306, 213,0 }, - { 313, 314, 0, 0, 7280, 340,0 }, - { 315, 316, 0, 0, 3693, 346,0 }, - { 317, 318, 0, 0, 13720, 4033,0 }, - { 108, 320, 0, 0, 40000, 66,0 }, - { 109, 321, 0, 0, 40000, 180,0 }, - { 322, 323, 0, 0, 40000, 73,0 }, - { 111,1530, 0, 0, 4053, 426,0 }, - { 324, 325, 0, 0, 626, 260,0 }, - { 326, 327, 0, 0, 1166, 400,0 }, - {1531,1532, 0, 0, 186, 340,0 }, - {1534,1535, 0, 0, 3240, 440,0 }, - { 330, 331, 0, 0, 1920, 360,0 }, - {1536,1537, 0, 0, 3020, 0,0 }, - {1538,1539, 0, 0, 1660, 846,0 }, - {1541, 339, 0, 0, 9213, 813,0 }, - {1542,1543, 0, 0, 993, 100,0 }, - {1544,3031, 0, 0, 860, 180,0 }, - {1546,3032, 0, 0, 40000, 80,0 }, - { 338, 339, 0, 0, 40000, 200,0 }, - { 340, 341, 0, 0, 40000, 0,0 }, - {1441,1442, 0, 0, 7393, 186,0 }, - { 207, 208, 0, 0, 14373, 126,0 }, - {1466,1467, 0, 0, 40000, 66,0 }, - {1468,1469, 0, 0, 40000, 46,0 }, - { 179, 180, 0, 0, 4080, 346,0 }, - {1449,1450, 0, 0, 8313, 3373,0 }, - { 35,1470, 0, 0, 40000, 0,0 }, - { 36,1471, 0, 0, 8093, 40,0 }, - { 235, 236, 0, 0, 2393, 333,0 }, - {1483,1484, 0, 0, 40000, 0,0 }, - { 55,1487, 0, 0, 40000, 80,0 }, - {1488,1489, 0, 0, 40000, 80,0 }, - {1492,1493, 0, 0, 40000, 66,0 }, - { 256, 257, 0, 0, 40000, 53,0 }, - { 260, 261, 0, 0, 40000, 86,0 }, - {1512,1513, 0, 0, 40000, 40,0 }, - {1510,1511, 0, 0, 40000, 80,0 }, - {1496,1498, 0, 0, 40000, 73,0 }, - { 295, 296, 0, 0, 40000, 340,0 }, - {1540, 339, 0, 0, 2466, 633,0 }, - { 398, 399, 35, 0, 1860, 226,0 }, - {1516,1517, 0, 0, 40000, 660,0 }, - {1550,3033, 35, 0, 213, 26,0 }, - {1556,1557, 35, 0, 1200, 426,0 }, - {1558,1559, 35, 0, 1173, 406,0 }, - {1570,1571, 35, 0, 1160, 140,0 }, - {1608,1609, 35, 0, 2100, 320,0 }, - {1595,1596, 35, 0, 220, 273,0 }, - { 159,1597, 35, 0, 220, 266,0 }, - {1610,1611, 35, 0, 220, 273,0 }, - { 397,1588, 35, 0, 253, 86,0 }, - {1606,1607, 35, 0, 133, 66,0 }, - { 145,1576, 35, 0, 180, 0,0 }, - {1612,1613, 35, 0, 526, 400,0 }, - {1577,1578, 35, 0, 506, 453,0 }, - {1614,1615, 35, 0, 773, 933,0 }, - { 305, 306, 0, 0, 40000, 1160,0 }, - {1522,1523, 0, 0, 40000, 0,0 }, - {1550,1551, 35, 0, 526, 146,0 }, - { 364, 365, 35, 0, 186, 20,0 }, - { 129,1549, 35, 0, 326, 133,0 }, - { 132,1552, 35, 0, 226, 113,0 }, - {1553,1554, 35, 0, 206, 73,0 }, - { 129,1548, 35, 0, 326, 133,0 }, - { 134,1555, 35, 0, 2580, 893,0 }, - {1560,1561, 35, 0, 600, 366,0 }, - {1562,1563, 35, 0, 40000, 0,0 }, - {1572,1573, 35, 0, 340, 133,0 }, - {1574,1575, 35, 0, 406, 226,0 }, - {1581,1582, 35, 0, 640, 213,0 }, - { 149,1583, 35, 0, 326, 20,0 }, - {1584,1585, 35, 0, 633, 240,0 }, - {1591,1592, 35, 0, 1226, 413,0 }, - {1568,1569, 35, 0, 1313, 460,0 }, - {1579,1580, 35, 0, 326, 0,0 }, - {1586,1587, 35, 0, 606, 220,0 }, - {1589,1590, 35, 0, 120, 86,0 }, - {1600,1601, 35, 0, 1326, 420,0 }, - {1602,1603, 35, 0, 706, 266,0 }, - {1604,1605, 35, 0, 4540, 1326,0 }, - { 391, 392, 35, 0, 360, 153,0 }, - { 391, 393, 35, 0, 453, 153,0 }, - {1598,1599, 35, 0, 1246, 346,0 }, - { 367, 368, 35, 0, 600, 153,0 }, - { 380, 381, 35, 0, 40000, 0,0 }, - { 374, 375, 35, 0, 40000, 0,0 }, - {1566,1567, 35, 0, 40000, 0,0 }, - {2306,2307, 35, 0, 7660, 1560,0 }, - {3034, 339, 35, 0, 5860, 426,0 }, - {2301,2302, 35, 0, 2146, 753,0 }, - {2305,1548, 35, 0, 326, 133,0 }, - {1595,1595, 35, 0, 220, 273,0 }, - {2303,2304, 35, 0, 186, 20,0 }, - {1560,2308, 35, 0, 600, 373,0 }, - {2309,2310, 35, 0, 40000, 0,0 }, - {1568,1568, 35, 0, 1280, 453,0 }, - {2311,2312, 35, 0, 360, 106,0 }, - {2313,2314, 35, 0, 620, 0,0 }, - {2315,2315, 35, 0, 106, 0,0 }, - {2316,2316, 35, 0, 506, 453,0 }, - {1612,1612, 35, 0, 526, 400,0 }, - {2317,2317, 35, 0, 640, 253,0 }, - {2318,2318, 35, 0, 326, 20,0 }, - {2319,2319, 35, 0, 453, 446,0 }, - {2320,2320, 35, 0, 466, 453,0 }, - {2321,2321, 35, 0, 120, 26,0 }, - {2322,2322, 35, 0, 1220, 406,0 }, - {2323,2323, 35, 0, 2360, 786,0 }, - {2324, 392, 35, 0, 353, 146,0 }, - {2324, 393, 35, 0, 453, 146,0 }, - {2325,2326, 35, 0, 533, 140,0 }, - {2327,2328, 35, 0, 1273, 393,0 }, - {2329,2330, 35, 0, 40000, 0,0 }, - {2331,2332, 35, 0, 40000, 0,0 }, - {3035,3036, 35, 0, 4133, 433,0 }, - {3037,3038, 35, 0, 1740, 286,0 }, - {1564,1564, 35, 0, 713, 273,0 }, - {3039,3039, 0, 0, 40000, 0,0 }, - {3040,3040, 0, 0, 6100, 146,0 }, - {3041,3041, 0, 0, 2386, 26,0 }, - {3042,3042, 0, 0, 4320, 80,0 }, - {3043,3043, 0, 0, 3433, 313,0 }, - {3044,3044, 0, 0, 6620, 2446,0 }, - {3045,3045, 0, 0, 3726, 1253,0 }, - {3046,3046, 0, 0, 40000, 133,0 }, - {3047,3047, 0, 0, 4566, 1253,0 }, - {3048,3048, 0, 0, 40000, 813,0 }, - {3049,3049, 0, 0, 18513, 1560,0 }, - {3050,3050, 0, 0, 2186, 426,0 }, - {3051,3051, 0, 0, 1186, 420,0 }, - {3052,3052, 0, 0, 766, 420,0 }, - {3053,3053, 0, 0, 14513, 4713,0 }, - {3054,3054, 0, 0, 15493, 1580,0 }, - {3055,3055, 0, 0, 40000, 66,0 }, - {3056,3056, 0, 0, 40000, 60,0 }, - {3057,3057, 0, 0, 4740, 100,0 }, - {3058,3058, 0, 0, 40000, 66,0 }, - {3059,3059, 0, 0, 40000, 73,0 }, - {3060,3060, 0, 0, 40000, 73,0 }, - {3061,3061, 0, 0, 40000, 0,0 }, - {3062,3062, 0, 0, 8373, 633,0 }, - {3063,3063, 0, 0, 7560, 133,0 }, - {3064,3064, 0, 0, 40000, 0,0 }, - {3065,3065, 0, 0, 40000, 86,0 }, - {3066,3066, 0, 0, 340, 140,0 }, - {3067,3067, 0, 0, 40000, 0,0 }, - {3068,3068, 0, 0, 40000, 166,0 }, - {3069,3069, 0, 0, 4280, 1466,0 }, - {3070,3070, 0, 0, 2193, 73,0 }, - {3071,3071, 0, 0, 4846, 100,0 }, - {3072,3072, 0, 0, 12740, 93,0 }, - {3073,3073, 0, 0, 6953, 200,0 }, - {3074,3074, 0, 0, 13780, 73,0 }, - {3075,3075, 0, 0, 40000, 73,0 }, - {3076,3076, 0, 0, 5860, 600,0 }, - {3077,3077, 0, 0, 2206, 73,0 }, - {3078,3078, 0, 0, 40000, 140,0 }, - {3079,3079, 0, 0, 40000, 53,0 }, - {3080,3080, 0, 0, 40000, 120,0 }, - {3081,3081, 0, 0, 40000, 140,0 }, - {3082,3082, 0, 0, 40000, 126,0 }, - {3083,3083, 0, 0, 360, 140,0 }, - {3084,3084, 0, 0, 8880, 1373,0 }, - {3085,3085, 0, 0, 593, 73,0 }, - {3086,3086, 0, 0, 40000, 193,0 }, - {3087,3087, 0, 0, 40000, 200,0 }, - {3088,3088, 0, 0, 40000, 160,0 }, - {3089,3089, 0, 0, 40000, 200,0 }, - {3090,3090, 0, 0, 40000, 53,0 }, - {3091,3091, 0, 0, 40000, 73,0 }, - {3092,3092, 0, 0, 40000, 73,0 }, - {3093,3093, 0, 0, 760, 213,0 }, - {3094,3094, 0, 0, 40000, 133,0 }, - {3095,3095, 0, 0, 40000, 220,0 }, - {3096,3096, 0, 0, 40000, 100,0 }, - {3097,3097, 0, 0, 40000, 73,0 }, - {3098,3098, 0, 0, 40000, 140,0 }, - {3099,3099, 0, 0, 40000, 140,0 }, - {3100,3100, 0, 0, 40000, 140,0 }, - {3101,3101, 0, 0, 40000, 73,0 }, - {3102,3102, 0, 0, 40000, 73,0 }, - {3103,3103, 0, 0, 40000, 73,0 }, - {3104,3104, 0, 0, 40000, 73,0 }, - {3105,3105, 0, 0, 40000, 66,0 }, - {3106,3106, 0, 0, 40000, 66,0 }, - {3107,3107, 0, 0, 40000, 73,0 }, - {3108,3108, 0, 0, 40000, 73,0 }, - {3109,3109, 0, 0, 40000, 73,0 }, - {3110,3110, 0, 0, 40000, 73,0 }, - {3111,3111, 0, 0, 40000, 86,0 }, - {3112,3112, 0, 0, 5393, 100,0 }, - {3113,3113, 0, 0, 40000, 60,0 }, - {3114,3114, 0, 0, 18500, 73,0 }, - {3115,3115, 0, 0, 40000, 93,0 }, - {3116,3116, 0, 0, 40000, 86,0 }, - {3117,3117, 0, 0, 40000, 173,0 }, - {3118,3118, 0, 0, 40000, 1353,0 }, - {3119,3119, 0, 0, 17506, 73,0 }, - {3120,3120, 0, 0, 40000, 100,0 }, - {3121,3121, 0, 0, 40000, 73,0 }, - {3122,3122, 0, 0, 5620, 193,0 }, - {3123,3123, 0, 0, 3700, 80,0 }, - {3124,3124, 0, 0, 40000, 66,0 }, - {3125,3125, 0, 0, 2740, 80,0 }, - {3126,3126, 0, 0, 8333, 173,0 }, - {3127,3127, 0, 0, 2226, 466,0 }, - {3128,3128, 0, 0, 340, 146,0 }, - {3129,3129, 0, 0, 19980, 6280,0 }, - {3130,3130, 0, 0, 353, 73,0 }, - {3131,3131, 35, 0, 566, 233,0 }, - {3132,3132, 35, 0, 226, 46,0 }, - {3133,3133, 35, 0, 40000, 100,0 }, - {3134,3134, 35, 0, 40000, 100,0 }, - {3135,3135, 35, 0, 360, 146,0 }, - {3061,3061, 35, 0, 40000, 0,0 }, - {3136,3136, 35, 0, 366, 20,0 }, - { 739, 739, 35, 0, 246, 20,0 }, - {3137,3137, 35, 0, 333, 33,0 }, - {3138,3138, 35, 0, 420, 166,0 }, - {3139,3139, 35, 0, 626, 240,0 }, - {3140,3140, 35, 0, 233, 100,0 }, - {3141,3141, 35, 0, 1166, 440,0 }, - {3142,3142, 35, 0, 166, 66,0 }, - {3143,3143, 35, 0, 1166, 440,0 }, - {3144,3144, 35, 0, 813, 100,0 }, - {3145,3145, 35, 0, 1040, 440,0 }, - {3146,3146, 35, 0, 40000, 0,0 }, - {3147,3147, 35, 0, 40000, 0,0 }, - {3148,3148, 35, 0, 180, 40,0 }, - {3149,3149, 35, 0, 40000, 0,0 }, - {3150,3150, 0, 0, 40000, 0,0 }, - {3151,3151, 0, 0, 4900, 240,0 }, - {3152,3152, 0, 0, 3480, 80,0 }, - {3153,3153, 0, 0, 3586, 86,0 }, - {3154,3154, 0, 0, 4626, 633,0 }, - {3155,3155, 0, 0, 4293, 2286,0 }, - {3156,3156, 0, 0, 13653, 0,0 }, - {3157,3157, 0, 0, 1206, 426,0 }, - {3158,3158, 0, 0, 653, 426,0 }, - {3159,3159, 0, 0, 40000, 0,0 }, - {3160,3160, 0, 0, 4633, 633,0 }, - {3161,3161, 0, 0, 40000, 73,0 }, - {3162,3162, 0, 0, 40000, 60,0 }, - {3163,3163, 0, 0, 40000, 146,0 }, - {3164,3164, 0, 0, 40000, 73,0 }, - {3165,3165, 0, 0, 40000, 73,0 }, - {3166,3166, 0, 0, 40000, 0,0 }, - {3167,3167, 0, 0, 40000, 66,0 }, - {3168,3168, 0, 0, 3680, 1180,0 }, - {3169,3169, 0, 0, 2406, 846,0 }, - {3170,3170, 0, 0, 1560, 73,0 }, - {3171,3171, 0, 0, 1946, 226,0 }, - {3172,3172, 0, 0, 4333, 13,0 }, - {3173,3173, 0, 0, 40000, 0,0 }, - {3174,3174, 0, 0, 40000, 0,0 }, - {3175,3175, 0, 0, 40000, 66,0 }, - {3176,3176, 0, 0, 40000, 180,0 }, - {3177,3177, 0, 0, 15380, 80,0 }, - {3178,3178, 0, 0, 18213, 73,0 }, - {3179,3179, 0, 0, 1706, 0,0 }, - {3180,3180, 0, 0, 5733, 1266,0 }, - {3181,3181, 0, 0, 40000, 0,0 }, - {3182,3182, 0, 0, 40000, 366,0 }, - {3183,3183, 0, 0, 40000, 66,0 }, - {3184,3184, 0, 0, 4786, 73,0 }, - {3185,3185, 0, 0, 5660, 720,0 }, - {3186,3186, 0, 0, 1293, 406,0 }, - {3187,3187, 0, 0, 40000, 0,0 }, - {3188,3188, 0, 0, 2686, 233,0 }, - {3189,3189, 0, 0, 40000, 0,0 }, - {3190,3190, 0, 0, 40000, 73,0 }, - {3191,3191, 0, 0, 40000, 0,0 }, - {3192,3192, 0, 0, 40000, 73,0 }, - {3193,3193, 0, 0, 40000, 0,0 }, - {3194,3194, 0, 0, 3920, 73,0 }, - {3195,3195, 0, 0, 40000, 73,0 }, - {3196,3196, 0, 0, 40000, 66,0 }, - {3197,3197, 0, 0, 40000, 80,0 }, - {3198,3198, 0, 0, 40000, 86,0 }, - {3199,3199, 0, 0, 40000, 60,0 }, - {3200,3200, 0, 0, 40000, 0,0 }, - {3201,3201, 0, 0, 40000, 353,0 }, - {3202,3202, 0, 0, 3920, 73,0 }, - {3203,3203, 0, 0, 5833, 813,0 }, - {3204,3204, 0, 0, 40000, 60,0 }, - {3205,3205, 0, 0, 40000, 73,0 }, - {3206,3206, 0, 0, 1400, 406,0 }, - {3207,3207, 0, 0, 40000, 66,0 }, - {3208,3208, 0, 0, 9066, 2220,0 }, - {3209,3209, 0, 0, 1473, 773,0 }, - {3210,3210, 0, 0, 40000, 120,0 }, - {3211,3211, 0, 0, 40000, 306,0 }, - {3212,3212, 0, 0, 9306, 3013,0 }, - {3213,3213, 0, 0, 40000, 60,0 }, - {3214,3214, 0, 0, 40000, 73,0 }, - {3215,3215, 0, 0, 40000, 73,0 }, - {3216,3216, 0, 0, 40000, 453,0 }, - {3217,3217, 0, 0, 40000, 3460,0 }, - {3218,3218, 0, 0, 40000, 453,0 }, - {3219,3219, 0, 0, 40000, 40,0 }, - {3220,3220, 0, 0, 40000, 3926,0 }, - {3221,3221, 0, 0, 40000, 4506,0 }, - {3222,3222, 0, 0, 4646, 646,0 }, - {3223,3223, 0, 0, 773, 100,0 }, - {3224,3224, 0, 0, 40000, 73,0 }, - {3225,3225, 0, 0, 40000, 173,0 }, - {3226,3226, 0, 0, 1606, 653,0 }, - {3227,3227, 0, 0, 2353, 806,0 }, - {3228,3228, 0, 0, 980, 360,0 }, - {3229,3229, 0, 0, 1193, 413,0 }, - { 499, 499, 0, 0, 266, 0,0 }, - {3230,3230, 0, 0, 973, 360,0 }, - {3231,3231, 0, 0, 273, 53,0 }, - {3232,3232, 0, 0, 726, 220,0 }, - {3233,3233, 0, 0, 19933, 6093,0 }, - {3234,3234, 0, 0, 40000, 0,0 }, - { 403, 403, 0, 0, 40000, 73,0 }, - {3235,3235, 0, 0, 4966, 233,0 }, - {3236,3236, 0, 0, 4946, 240,0 }, - {3237,3237, 0, 0, 4946, 233,0 }, - {3238,3238, 0, 0, 4640, 1613,0 }, - {3239,3239, 0, 0, 2360, 806,0 }, - {3240,3240, 0, 0, 4466, 200,0 }, - {3241,3241, 0, 0, 40000, 73,0 }, - {3242,3242, 0, 0, 40000, 73,0 }, - {3243,3243, 0, 0, 40000, 73,0 }, - {3244,3244, 0, 0, 40000, 73,0 }, - {3245,3245, 0, 0, 40000, 240,0 }, - {3246,3246, 0, 0, 40000, 226,0 }, - {3247,3247, 0, 0, 40000, 233,0 }, - {3248,3248, 0, 0, 40000, 240,0 }, - {3249,3249, 0, 0, 4306, 1253,0 }, - {3250,3250, 0, 0, 3873, 1206,0 }, - {3251,3251, 0, 0, 4640, 633,0 }, - {3252,3252, 0, 0, 1233, 80,0 }, - {3253,3253, 0, 0, 1233, 26,0 }, - {3254,3254, 0, 0, 1233, 26,0 }, - {3255,3255, 0, 0, 4573, 1253,0 }, - {3256,3256, 0, 0, 3793, 1240,0 }, - {3257,3257, 0, 0, 40000, 73,0 }, - {3258,3258, 0, 0, 40000, 73,0 }, - {3259,3259, 0, 0, 40000, 140,0 }, - {3260,3260, 0, 0, 40000, 146,0 }, - {3261,3261, 0, 0, 40000, 80,0 }, - {3262,3262, 0, 0, 5953, 200,0 }, - {3263,3263, 0, 0, 5926, 200,0 }, - {3264,3264, 0, 0, 5866, 26,0 }, - {3265,3265, 0, 0, 18573, 6153,0 }, - {3266,3266, 0, 0, 40000, 2093,0 }, - {3267,3267, 0, 0, 40000, 73,0 }, - {3268,3268, 0, 0, 18626, 1553,0 }, - {3269,3269, 0, 0, 40000, 1820,0 }, - {3270,3270, 0, 0, 40000, 500,0 }, - {3271,3271, 0, 0, 18206, 5900,0 }, - {3272,3272, 0, 0, 14200, 93,0 }, - {3273,3273, 0, 0, 40000, 2873,0 }, - {3274,3274, 0, 0, 14960, 4913,0 }, - {3275,3275, 0, 0, 40000, 86,0 }, - {3276,3276, 0, 0, 40000, 826,0 }, - {3277,3277, 0, 0, 40000, 200,0 }, - {3278,3278, 0, 0, 40000, 340,0 }, - {3279,3279, 0, 0, 13220, 2500,0 }, - {3280,3280, 0, 0, 40000, 100,0 }, - {3281,3281, 0, 0, 40000, 1026,0 }, - {3282,3282, 0, 0, 40000, 366,0 }, - {3283,3283, 0, 0, 40000, 386,0 }, - {3284,3284, 0, 0, 40000, 0,0 }, - {3285,3285, 0, 0, 40000, 0,0 }, - {3286,3286, 0, 0, 40000, 140,0 }, - {3287,3287, 0, 0, 40000, 53,0 }, - {3288,3288, 0, 0, 40000, 120,0 }, - {3289,3289, 0, 0, 8866, 1366,0 }, - {3290,3290, 0, 0, 4193, 1400,0 }, - {3291,3291, 0, 0, 8353, 673,0 }, - {3292,3292, 0, 0, 8353, 673,0 }, - {3293,3293, 0, 0, 8400, 593,0 }, - {3294,3294, 0, 0, 8440, 666,0 }, - {3295,3295, 0, 0, 9600, 1580,0 }, - {3296,3296, 0, 0, 40000, 46,0 }, - {3297,3297, 0, 0, 40000, 0,0 }, - {3298,3298, 0, 0, 1653, 93,0 }, - {3299,3299, 0, 0, 2706, 73,0 }, - {3300,3300, 0, 0, 11680, 26,0 }, - {3301,3301, 0, 0, 6500, 340,0 }, - {3302,3302, 0, 0, 40000, 0,0 }, - {3303,3303, 0, 0, 40000, 0,0 }, - {3304,3304, 0, 0, 40000, 73,0 }, - {3305,3305, 0, 0, 40000, 73,0 }, - {3306,3306, 0, 0, 40000, 73,0 }, - {3307,3307, 0, 0, 40000, 73,0 }, - {3308,3308, 0, 0, 40000, 73,0 }, - {3309,3309, 0, 0, 40000, 73,0 }, - {3310,3310, 0, 0, 40000, 73,0 }, - {3311,3311, 0, 0, 40000, 73,0 }, - {3312,3312, 0, 0, 40000, 73,0 }, - {3313,3313, 0, 0, 40000, 133,0 }, - {3314,3314, 0, 0, 40000, 126,0 }, - {3315,3315, 0, 0, 40000, 73,0 }, - {3316,3316, 0, 0, 40000, 73,0 }, - {3317,3317, 0, 0, 40000, 73,0 }, - {3318,3318, 0, 0, 40000, 200,0 }, - {3319,3319, 0, 0, 40000, 133,0 }, - {3320,3320, 0, 0, 40000, 0,0 }, - {3321,3321, 0, 0, 40000, 240,0 }, - {3322,3322, 0, 0, 40000, 220,0 }, - {3323,3323, 0, 0, 40000, 226,0 }, - {3324,3324, 0, 0, 40000, 100,0 }, - {3325,3325, 0, 0, 40000, 140,0 }, - {3326,3326, 0, 0, 40000, 0,0 }, - {3327,3327, 0, 0, 40000, 426,0 }, - {3328,3328, 0, 0, 40000, 426,0 }, - {3329,3329, 0, 0, 3680, 1220,0 }, - {3330,3330, 0, 0, 40000, 533,0 }, - {3331,3331, 0, 0, 40000, 813,0 }, - {3332,3332, 0, 0, 14506, 4706,0 }, - {3333,3333, 0, 0, 766, 420,0 }, - {3334,3334, 0, 0, 40000, 1566,0 }, - {3335,3335, 0, 0, 40000, 120,0 }, - {3336,3336, 0, 0, 40000, 2380,0 }, - {3337,3337, 0, 0, 5666, 300,0 }, - {3338,3338, 0, 0, 40000, 73,0 }, - {3339,3339, 0, 0, 40000, 2513,0 }, - {3340,3340, 0, 0, 1260, 826,0 }, - {3341,3341, 0, 0, 2420, 413,0 }, - {3342,3342, 0, 0, 626, 240,0 }, - {3343,3343, 0, 0, 273, 60,0 }, - {3344,3344, 0, 0, 540, 20,0 }, - {3345,3345, 0, 0, 540, 20,0 }, - {3346,3346, 0, 0, 540, 20,0 }, - {3347,3347, 0, 0, 1153, 760,0 }, - {3348,3348, 0, 0, 40000, 100,0 }, - {3349,3349, 0, 0, 7326, 2380,0 }, - {3350,3350, 0, 0, 40000, 4426,0 }, - {3351,3351, 0, 0, 7413, 2493,0 }, - {3352,3352, 0, 0, 253, 20,0 }, - {3353,3353, 0, 0, 246, 33,0 }, - {3354,3354, 0, 0, 286, 13,0 }, - {3355,3355, 0, 0, 953, 13,0 }, - {3356,3356, 0, 0, 293, 20,0 }, - { 142, 142, 20, 0, 1893, 620,0 }, - {3357,1451, 0, 4, 2373, 780,0 }, - {3358,3359, 0, 4, 9260, 246,0 }, - {3360,1455, 0, 4, 40000, 0,0 }, - {3361,1463, 0, 4, 40000, 266,0 }, - { 225,3362, 0, 4, 7993, 100,0 }, - {3363,1545, 0, 4, 293, 86,0 }, - {3364,1547, 0, 4, 40000, 180,0 }, - {3365,3366, 39, 4, 66, 0,0 }, - {3367, 368, 58, 4, 173, 0,0 }, - {3368,1551, 48, 4, 520, 200,0 }, - {3368,3033, 49, 4, 53, 0,0 }, - {3368,3033, 51, 4, 53, 0,0 }, - {3368,3033, 54, 4, 60, 0,0 }, - {3368,3033, 57, 4, 60, 0,0 }, - {3368,3033, 60, 4, 60, 0,0 }, - {3369,3370, 70, 4, 840, 0,0 }, - {1564,1565, 80, 4, 220, 0,0 }, - {3371,1571, 44, 4, 420, 0,0 }, - {3372,3372, 0, 0, 8366, 666,0 }, - {3373,3373, 0, 0, 8366, 666,0 }, - {3374,3374, 0, 0, 3773, 73,0 }, - {3375,3375, 0, 0, 8366, 666,0 }, - {3376,3376, 0, 0, 4693, 26,0 }, - {3377,3377, 0, 0, 7400, 80,0 }, - {3378,3378, 0, 0, 3586, 80,0 }, - {3379,3379, 0, 0, 8366, 666,0 }, - {3380,3380, 0, 0, 3786, 1240,0 }, - {3381,3381, 0, 0, 9013, 1466,0 }, - {3382,3382, 0, 0, 1200, 73,0 }, - {3383,3383, 0, 0, 8146, 1446,0 }, - {3384,3384, 0, 0, 3660, 1206,0 }, - {3385,3385, 0, 0, 200, 100,0 }, - {3386,3386, 0, 0, 40000, 0,0 }, - {3387,3387, 0, 0, 1213, 426,0 }, - {3388,3388, 0, 0, 40000, 2573,0 }, - {3389,3389, 0, 0, 40000, 3446,0 }, - {3390,3390, 0, 0, 40000, 333,0 }, - {3391,3391, 0, 0, 40000, 73,0 }, - {3392,3392, 0, 0, 40000, 93,0 }, - {3393,3393, 0, 0, 40000, 73,0 }, - {3394,3394, 0, 0, 40000, 73,0 }, - {3395,3395, 0, 0, 40000, 73,0 }, - {3396,3396, 0, 0, 2193, 413,0 }, - {3397,3397, 0, 0, 14606, 2886,0 }, - {3398,3398, 0, 0, 10626, 4520,0 }, - {3399,3399, 0, 0, 2413, 100,0 }, - {3400,3400, 0, 0, 3593, 1140,0 }, - {3401,3401, 0, 0, 40000, 146,0 }, - {3402,3402, 0, 0, 40000, 86,0 }, - {3403,3403, 0, 0, 40000, 86,0 }, - {3404,3404, 0, 0, 9366, 106,0 }, - {3405,3405, 0, 0, 40000, 73,0 }, - {3406,3406, 0, 0, 40000, 0,0 }, - {3407,3407, 0, 0, 40000, 0,0 }, - {3408,3408, 0, 0, 1626, 400,0 }, - {3409,3409, 0, 0, 4473, 2933,0 }, - {3410,3410, 0, 0, 40000, 66,0 }, - {3411,3411, 0, 0, 40000, 0,0 }, - {3412,3412, 0, 0, 40000, 253,0 }, - {3413,3413, 0, 0, 40000, 233,0 }, - {3414,3414, 0, 0, 40000, 346,0 }, - {3415,3415, 0, 0, 1966, 26,0 }, - {3416,3416, 0, 0, 40000, 366,0 }, - {3417,3417, 0, 0, 2266, 386,0 }, - {3418,3418, 0, 0, 40000, 0,0 }, - {3419,3419, 0, 0, 2313, 766,0 }, - {3420,3420, 0, 0, 40000, 340,0 }, - {3421,3421, 0, 0, 40000, 346,0 }, - {3422,3422, 0, 0, 40000, 340,0 }, - {3423,3423, 0, 0, 40000, 353,0 }, - {3424,3424, 0, 0, 40000, 353,0 }, - {3425,3425, 0, 0, 40000, 226,0 }, - {3426,3426, 0, 0, 40000, 73,0 }, - {3427,3427, 0, 0, 940, 253,0 }, - {3428,3428, 0, 0, 40000, 73,0 }, - {3429,3429, 0, 0, 40000, 80,0 }, - {3430,3430, 0, 0, 40000, 240,0 }, - {3431,3431, 0, 0, 40000, 80,0 }, - {3432,3432, 0, 0, 40000, 73,0 }, - {3433,3433, 0, 0, 40000, 73,0 }, - {3434,3434, 0, 0, 40000, 73,0 }, - {3435,3435, 0, 0, 40000, 73,0 }, - {3436,3436, 0, 0, 40000, 73,0 }, - {3437,3437, 0, 0, 40000, 73,0 }, - {3438,3438, 0, 0, 40000, 73,0 }, - {3439,3439, 0, 0, 40000, 73,0 }, - {3440,3440, 0, 0, 40000, 73,0 }, - {3441,3441, 0, 0, 40000, 73,0 }, - {3442,3442, 0, 0, 40000, 66,0 }, - {3443,3443, 0, 0, 40000, 73,0 }, - {3444,3444, 0, 0, 40000, 80,0 }, - {3445,3445, 0, 0, 40000, 66,0 }, - {3446,3446, 0, 0, 40000, 66,0 }, - {3447,3447, 0, 0, 40000, 66,0 }, - {3448,3448, 0, 0, 40000, 66,0 }, - {3449,3449, 0, 0, 40000, 80,0 }, - {3450,3450, 0, 0, 40000, 353,0 }, - {3451,3451, 0, 0, 40000, 0,0 }, - {3452,3452, 0, 0, 18440, 100,0 }, - {3453,3453, 0, 0, 18086, 100,0 }, - {3454,3454, 0, 0, 266, 66,0 }, - {3455,3455, 0, 0, 40000, 80,0 }, - {3456,3456, 0, 0, 40000, 100,0 }, - {3457,3457, 0, 0, 40000, 80,0 }, - {3458,3458, 0, 0, 40000, 120,0 }, - {3459,3459, 0, 0, 40000, 93,0 }, - {3460,3460, 0, 0, 40000, 233,0 }, - {3461,3461, 0, 0, 40000, 0,0 }, - {3462,3462, 0, 0, 40000, 86,0 }, - {3463,3463, 0, 0, 40000, 820,0 }, - {3464,3464, 0, 0, 40000, 4986,0 }, - {3465,3465, 0, 0, 40000, 146,0 }, - {3466,3466, 0, 0, 40000, 100,0 }, - {3467,3467, 0, 0, 40000, 3346,0 }, - {3468,3468, 0, 0, 40000, 660,0 }, - {3469,3469, 0, 0, 40000, 366,0 }, - {3470,3470, 0, 0, 40000, 1480,0 }, - {3471,3471, 0, 0, 40000, 646,0 }, - {3472,3472, 0, 0, 40000, 2673,0 }, - {3473,3473, 0, 0, 40000, 2500,0 }, - {3474,3474, 0, 0, 40000, 2513,0 }, - {3475,3475, 0, 0, 40000, 66,0 }, - {3476,3476, 0, 0, 9600, 1580,0 }, - {3477,3477, 0, 0, 40000, 46,0 }, - {3478,3478, 0, 0, 10673, 100,0 }, - {3479,3479, 0, 0, 2333, 800,0 }, - {3480,3480, 0, 0, 3673, 1200,0 }, - {3481,3481, 0, 0, 40000, 73,0 }, - {3482,3482, 0, 0, 40000, 146,0 }, - {3483,3483, 0, 0, 40000, 73,0 }, - {3484,3484, 0, 0, 2266, 726,0 }, - {3485,3485, 0, 0, 333, 140,0 }, - {3486,3486, 0, 0, 2286, 746,0 }, - {3487,3487, 0, 0, 293, 126,0 }, - {3488,3488, 0, 0, 3700, 1213,0 }, - {3489,3489, 0, 0, 3773, 1186,0 }, - {3490,3490, 0, 0, 3646, 1200,0 }, - {3491,3491, 0, 0, 3020, 73,0 }, - {3492,3492, 0, 0, 786, 273,0 }, - {3493,3493, 0, 0, 40000, 146,0 }, - {3494,3494, 0, 0, 40000, 3093,0 }, - {3495,3495, 0, 0, 273, 60,0 }, - {3496,3496, 0, 0, 40000, 73,0 }, - {3497,3497, 0, 0, 40000, 73,0 }, - {3498,3498, 0, 0, 40000, 3093,0 }, - {3499,3499, 0, 0, 40000, 240,0 }, - {3500,3500, 0, 2, 6, 0,0 }, - { 739, 739, 46, 0, 220, 33,0 }, - {3501,3501, 47, 0, 973, 93,0 }, - {3502,3502, 64, 0, 126, 66,0 }, - {3503,3503, 40, 0, 340, 146,0 }, - {3504,3504, 48, 0, 100, 0,0 }, - {3505,3505, 48, 0, 286, 133,0 }, - {3506,3506, 46, 0, 466, 166,0 }, - {3507,3507,111, 0, 226, 113,0 }, - {3508,3508, 49, 0, 473, 166,0 }, - {3509,3509, 56, 0, 126, 40,0 }, - {3510,3510, 52, 0, 520, 206,0 }, - {3511,3511, 96, 0, 1346, 473,0 }, - {3510,3510, 54, 0, 513, 206,0 }, - {3512,3512, 57, 0, 973, 266,0 }, - {3513,3513, 82, 0, 1580, 553,0 }, - {3510,3510, 60, 0, 506, 200,0 }, - {3514,3514, 60, 0, 1886, 646,0 }, - {3515,3515, 92, 0, 1026, 520,0 }, - {3516,3516, 60, 0, 180, 93,0 }, - {3517,3517, 58, 0, 213, 213,0 }, - {3518,3518, 22, 0, 2300, 766,0 }, - {3519,3519, 60, 0, 1873, 653,0 }, - {3520,3520, 72, 0, 260, 93,0 }, - {3521,3521, 77, 0, 253, 93,0 }, - {3522,3522, 70, 0, 206, 93,0 }, - {3523,3523, 75, 0, 173, 93,0 }, - {3524,3524, 69, 0, 406, 113,0 }, - {3525,3525, 59, 0, 380, 160,0 }, - {3526,3526, 48, 0, 373, 40,0 }, - {3527,3527, 89, 0, 433, 180,0 }, - {3528,3528, 84, 0, 813, 180,0 }, - {3529,3529, 33, 0, 240, 53,0 }, - {3530,3530, 55, 0, 220, 86,0 }, - {3531,3531, 58, 0, 526, 200,0 }, - {3532,3532, 52, 0, 526, 193,0 }, - {3533,3533, 57, 0, 166, 80,0 }, - {3534,3534, 57, 0, 240, 100,0 }, - {3535,3535, 85, 0, 220, 113,0 }, - {3536,3536, 68, 0, 173, 93,0 }, - {3536,3536, 61, 0, 220, 113,0 }, - {3537,3537, 64, 0, 346, 53,0 }, - {3538,3538, 44, 0, 1080, 346,0 }, - {3539,3539,100, 0, 193, 20,0 }, - {3540,3540,100, 0, 793, 26,0 }, - {3541,3541, 0, 0, 14166, 320,0 }, - {3542,3542, 0, 0, 3873, 1613,0 }, - {3543,3543, 0, 0, 3586, 86,0 }, - {3544,3544, 0, 0, 7406, 2486,0 }, - {3545,3545, 0, 0, 4640, 1560,0 }, - {3546,3546, 0, 0, 446, 440,0 }, - {3547,3547, 0, 0, 9253, 3100,0 }, - {3548,3548, 0, 0, 4646, 646,0 }, - {3549,3549, 0, 0, 40000, 66,0 }, - {3550,3550, 0, 0, 40000, 73,0 }, - {3551,3551, 0, 0, 40000, 113,0 }, - {3552,3552, 0, 0, 40000, 73,0 }, - {3553,3553, 0, 0, 40000, 73,0 }, - {3554,3554, 0, 0, 40000, 0,0 }, - {3555,3555, 0, 0, 40000, 60,0 }, - {3556,3556, 0, 0, 3673, 1206,0 }, - {3557,3557, 0, 0, 3706, 1293,0 }, - {3558,3558, 0, 0, 5693, 1126,0 }, - {3559,3559, 0, 0, 2406, 846,0 }, - {3560,3560, 0, 0, 40000, 66,0 }, - {3561,3561, 0, 0, 40000, 73,0 }, - {3562,3562, 0, 0, 4333, 13,0 }, - {3563,3563, 0, 0, 3700, 66,0 }, - {3564,3564, 0, 0, 40000, 0,0 }, - {3565,3565, 0, 0, 3713, 1260,0 }, - {3566,3566, 0, 0, 1140, 126,0 }, - {3567,3567, 0, 0, 40000, 186,0 }, - {3568,3568, 0, 0, 40000, 0,0 }, - {3569,3569, 0, 0, 14400, 6,0 }, - {3570,3570, 0, 0, 14580, 66,0 }, - {3571,3571, 0, 0, 40000, 73,0 }, - {3572,3572, 0, 0, 40000, 353,0 }, - {3573,3573, 0, 0, 40000, 0,0 }, - {3574,3574, 0, 0, 40000, 173,0 }, - {3575,3575, 0, 0, 1833, 600,0 }, - {3576,3576, 0, 0, 40000, 0,0 }, - {3577,3577, 0, 0, 40000, 206,0 }, - {3578,3578, 0, 0, 40000, 46,0 }, - {3579,3579, 0, 0, 40000, 73,0 }, - {3580,3580, 0, 0, 9166, 2900,0 }, - {3581,3581, 0, 0, 5640, 680,0 }, - {3582,3582, 0, 0, 640, 220,0 }, - {3583,3583, 0, 0, 40000, 53,0 }, - {3584,3584, 0, 0, 40000, 26,0 }, - {3585,3585, 0, 0, 40000, 0,0 }, - {3586,3586, 0, 0, 40000, 66,0 }, - {3587,3587, 0, 0, 40000, 60,0 }, - {3588,3588, 0, 0, 40000, 0,0 }, - {3589,3589, 0, 0, 40000, 73,0 }, - {3590,3590, 0, 0, 40000, 0,0 }, - {3591,3591, 0, 0, 40000, 0,0 }, - {3592,3592, 0, 0, 3780, 73,0 }, - {3593,3593, 0, 0, 40000, 0,0 }, - {3594,3594, 0, 0, 3786, 73,0 }, - {3595,3595, 0, 0, 40000, 73,0 }, - {3596,3596, 0, 0, 40000, 66,0 }, - {3597,3597, 0, 0, 40000, 73,0 }, - {3598,3598, 0, 0, 40000, 53,0 }, - {3599,3599, 0, 0, 40000, 426,0 }, - {3600,3600, 0, 0, 40000, 133,0 }, - {3601,3601, 0, 0, 40000, 66,0 }, - {3602,3602, 0, 0, 40000, 433,0 }, - {3603,3603, 0, 0, 393, 126,0 }, - {3604,3604, 0, 0, 40000, 66,0 }, - {3605,3605, 0, 0, 40000, 353,0 }, - {3606,3606, 0, 0, 3813, 73,0 }, - {3607,3607, 0, 0, 5793, 780,0 }, - {3608,3608, 0, 0, 40000, 73,0 }, - {3609,3609, 0, 0, 40000, 86,0 }, - {3610,3610, 0, 0, 820, 206,0 }, - {3611,3611, 0, 0, 40000, 66,0 }, - {3612,3612, 0, 0, 40000, 200,0 }, - {3613,3613, 0, 0, 18186, 720,0 }, - {3614,3614, 0, 0, 40000, 0,0 }, - {3615,3615, 0, 0, 40000, 493,0 }, - {3616,3616, 0, 0, 40000, 306,0 }, - {3617,3617, 0, 0, 2166, 600,0 }, - {3618,3618, 0, 0, 40000, 73,0 }, - {3619,3619, 0, 0, 40000, 3073,0 }, - {3620,3620, 0, 0, 2333, 413,0 }, - {3621,3621, 0, 0, 14880, 73,0 }, - {3622,3622, 0, 0, 40000, 66,0 }, - {3623,3623, 0, 0, 40000, 73,0 }, - {3624,3624, 0, 0, 40000, 1873,0 }, - {3625,3625, 0, 0, 40000, 446,0 }, - {3626,3626, 0, 0, 40000, 3126,0 }, - {3627,3627, 0, 0, 18446, 6140,0 }, - {3628,3628, 0, 0, 1113, 240,0 }, - {3629,3629, 0, 0, 40000, 3600,0 }, - {3630,3630, 0, 0, 40000, 4726,0 }, - {3631,3631, 0, 0, 40000, 0,0 }, - {3632,3632, 0, 0, 2893, 606,0 }, - {3633,3633, 0, 0, 40000, 0,0 }, - {3634,3634, 0, 0, 40000, 0,0 }, - {3635,3635, 0, 0, 40000, 173,0 }, - {3636,3636, 0, 0, 40000, 60,0 }, - {3637,3637, 0, 0, 40000, 0,0 }, - {3638,3638, 0, 0, 986, 326,0 }, - {3639,3639, 0, 0, 1873, 646,0 }, - {3640,3640, 0, 0, 200, 260,0 }, - {3641,3641, 0, 0, 1180, 393,0 }, - {3642,3642, 0, 0, 266, 0,0 }, - {3643,3643, 0, 0, 313, 126,0 }, - {3644,3644, 0, 0, 406, 253,0 }, - {3645,3645, 0, 0, 1013, 813,0 }, - {3646,3646, 0, 0, 273, 53,0 }, - {3647,3647, 0, 0, 720, 213,0 }, - {3648,3648, 0, 0, 386, 120,0 }, - {3649,3649, 0, 0, 40000, 766,0 }, - {3650,3650, 0, 0, 40000, 66,0 }, - {3651,3651, 0, 0, 40000, 73,0 }, - {3652,3652, 0, 0, 1186, 426,0 }, - {3653,3653, 0, 0, 16720, 240,0 }, - {3654,3654, 0, 0, 8026, 246,0 }, - {3655,3655, 0, 0, 18186, 140,0 }, - {3656,3656, 0, 0, 14566, 200,0 }, - {3657,3657, 0, 0, 7973, 20,0 }, - {3658,3658, 0, 0, 4446, 86,0 }, - {3659,3659, 0, 0, 4473, 100,0 }, - {3660,3660, 0, 0, 8646, 153,0 }, - {3661,3661, 0, 0, 3726, 660,0 }, - {3662,3662, 0, 0, 1893, 653,0 }, - {3663,3663, 0, 0, 1933, 760,0 }, - {3664,3664, 0, 0, 9160, 240,0 }, - {3665,3665, 0, 0, 1133, 100,0 }, - {3666,3666, 0, 0, 633, 233,0 }, - {3667,3667, 0, 0, 9153, 3060,0 }, - {3668,3668, 0, 0, 2166, 406,0 }, - {3669,3669, 0, 0, 40000, 66,0 }, - {3670,3670, 0, 0, 40000, 73,0 }, - {3671,3671, 0, 0, 40000, 73,0 }, - {3672,3672, 0, 0, 40000, 73,0 }, - {3673,3673, 0, 0, 40000, 346,0 }, - {3674,3674, 0, 0, 40000, 353,0 }, - {3675,3675, 0, 0, 40000, 200,0 }, - {3676,3676, 0, 0, 40000, 320,0 }, - {3677,3677, 0, 0, 4646, 100,0 }, - {3678,3678, 0, 0, 4426, 133,0 }, - {3679,3679, 0, 0, 4633, 100,0 }, - {3680,3680, 0, 0, 2266, 133,0 }, - {3681,3681, 0, 0, 2346, 53,0 }, - {3682,3682, 0, 0, 40000, 66,0 }, - {3683,3683, 0, 0, 9686, 173,0 }, - {3684,3684, 0, 0, 14300, 66,0 }, - {3685,3685, 0, 0, 40000, 0,0 }, - {3686,3686, 0, 0, 40000, 0,0 }, - {3687,3687, 0, 0, 40000, 0,0 }, - {3688,3688, 0, 0, 8613, 73,0 }, - {3689,3689, 0, 0, 40000, 0,0 }, - {3690,3690, 0, 0, 40000, 0,0 }, - {3691,3691, 0, 0, 40000, 0,0 }, - {3692,3692, 0, 0, 40000, 0,0 }, - {3693,3693, 0, 0, 40000, 393,0 }, - {3694,3694, 0, 0, 40000, 126,0 }, - {3695,3695, 0, 0, 40000, 120,0 }, - {3696,3696, 0, 0, 40000, 0,0 }, - {3697,3697, 0, 0, 40000, 226,0 }, - {3698,3698, 0, 0, 7420, 1186,0 }, - {3699,3699, 0, 0, 3280, 1726,0 }, - {3700,3700, 0, 0, 3680, 1220,0 }, - {3701,3701, 0, 0, 40000, 480,0 }, - {3702,3702, 0, 0, 40000, 306,0 }, - {3703,3703, 0, 0, 40000, 433,0 }, - {3704,3704, 0, 0, 40000, 133,0 }, - {3705,3705, 0, 0, 40000, 0,0 }, - {3706,3706, 0, 0, 40000, 0,0 }, - {3707,3707, 0, 0, 1166, 380,0 }, - {3708,3708, 0, 0, 40000, 140,0 }, - {3709,3709, 0, 0, 40000, 126,0 }, - {3710,3710, 0, 0, 40000, 100,0 }, - {3711,3711, 0, 0, 40000, 66,0 }, - {3712,3712, 0, 0, 40000, 226,0 }, - {3713,3713, 0, 0, 40000, 133,0 }, - {3714,3714, 0, 0, 40000, 73,0 }, - {3715,3715, 0, 0, 40000, 226,0 }, - {3716,3716, 0, 0, 40000, 100,0 }, - {3717,3717, 0, 0, 40000, 80,0 }, - {3718,3718, 0, 0, 40000, 100,0 }, - {3719,3719, 0, 0, 40000, 73,0 }, - {3720,3720, 0, 0, 40000, 73,0 }, - {3721,3721, 0, 0, 40000, 73,0 }, - {3722,3722, 0, 0, 40000, 126,0 }, - {3723,3723, 0, 0, 40000, 80,0 }, - {3724,3724, 0, 0, 40000, 73,0 }, - {3725,3725, 0, 0, 40000, 86,0 }, - {3726,3726, 0, 0, 40000, 100,0 }, - {3727,3727, 0, 0, 40000, 0,0 }, - {3728,3728, 0, 0, 40000, 126,0 }, - {3729,3729, 0, 0, 40000, 133,0 }, - {3730,3730, 0, 0, 40000, 140,0 }, - {3731,3731, 0, 0, 40000, 73,0 }, - {3732,3732, 0, 0, 40000, 60,0 }, - {3733,3733, 0, 0, 40000, 93,0 }, - {3734,3734, 0, 0, 40000, 80,0 }, - {3735,3735, 0, 0, 40000, 66,0 }, - {3736,3736, 0, 0, 40000, 0,0 }, - {3737,3737, 0, 0, 40000, 220,0 }, - {3738,3738, 0, 0, 40000, 80,0 }, - {3739,3739, 0, 0, 40000, 400,0 }, - {3740,3740, 0, 0, 40000, 1373,0 }, - {3741,3741, 0, 0, 40000, 86,0 }, - {3742,3742, 0, 0, 40000, 1313,0 }, - {3743,3743, 0, 0, 40000, 0,0 }, - {3744,3744, 0, 0, 11486, 593,0 }, - {3745,3745, 0, 0, 40000, 1246,0 }, - {3746,3746, 0, 0, 40000, 140,0 }, - {3747,3747, 0, 0, 14386, 2680,0 }, - {3748,3748, 0, 0, 40000, 653,0 }, - {3749,3749, 0, 0, 2286, 713,0 }, - {3750,3750, 0, 0, 40000, 253,0 }, - {3751,3751, 0, 0, 6933, 406,0 }, - {3752,3752, 0, 0, 40000, 1313,0 }, - {3753,3753, 0, 0, 40000, 1440,0 }, - {3754,3754, 0, 0, 40000, 73,0 }, - {3755,3755, 0, 0, 11100, 420,0 }, - {3756,3756, 0, 0, 6493, 320,0 }, - {3757,3757, 0, 0, 3486, 126,0 }, - {3758,3758, 0, 0, 6620, 2133,0 }, - {3759,3759, 0, 0, 1180, 413,0 }, - {3760,3760, 0, 0, 40000, 73,0 }, - {3761,3761, 0, 0, 40000, 73,0 }, - {3762,3762, 0, 0, 40000, 66,0 }, - {3763,3763, 0, 0, 4580, 413,0 }, - {3764,3764, 0, 0, 340, 146,0 }, - {3765,3765, 0, 0, 1166, 400,0 }, - {3766,3766, 0, 0, 1346, 660,0 }, - {3767,3767, 0, 0, 1260, 393,0 }, - {3768,3768, 0, 0, 3646, 1186,0 }, - {3769,3769, 0, 0, 2713, 400,0 }, - {3770,3770, 0, 0, 1780, 73,0 }, - {3771,3771, 0, 0, 800, 213,0 }, - {3772,3772, 0, 0, 660, 173,0 }, - {3773,3773, 0, 0, 12146, 73,0 }, - {3774,3774, 0, 0, 273, 60,0 }, - {3775,3775, 0, 0, 40000, 73,0 }, - {3776,3776, 0, 0, 380, 53,0 }, - {3777,3777, 0, 0, 40000, 200,0 }, - {3778,3778, 0, 0, 586, 20,0 }, - {3779,3779, 0, 2, 6, 0,0 }, - { 738, 738, 44, 0, 840, 340,0 }, - {3780,3780, 36, 0, 7366, 140,0 }, - {3781,3781, 32, 0, 100, 0,0 }, - {2030,2030, 60, 0, 293, 126,0 }, - {3782,3782, 24, 0, 100, 0,0 }, - {3783,3783, 60, 0, 126, 73,0 }, - {3784,3784, 44, 0, 393, 93,0 }, - { 132, 132, 44, 0, 173, 100,0 }, - {3785,3785, 47, 0, 393, 93,0 }, - { 152, 152, 44, 0, 213, 86,0 }, - {3784,3784, 50, 0, 393, 93,0 }, - { 139, 139, 44, 0, 293, 100,0 }, - {3784,3784, 54, 0, 393, 93,0 }, - {3784,3784, 57, 0, 393, 93,0 }, - {3786,3786, 60, 0, 1900, 666,0 }, - {3784,3784, 60, 0, 393, 93,0 }, - {3787,3787, 60, 0, 1900, 666,0 }, - {3788,3788, 60, 0, 1886, 666,0 }, - {3789,3789, 60, 0, 1866, 653,0 }, - {3790,3790, 60, 0, 1873, 633,0 }, - {3791,3791, 44, 0, 946, 333,0 }, - {2037,2037, 44, 0, 213, 126,0 }, - { 144, 144, 44, 0, 213, 126,0 }, - {2038,2038, 44, 0, 106, 0,0 }, - {3792,3792, 44, 0, 380, 360,0 }, - {3793,3793, 44, 0, 520, 206,0 }, - {3794,3794, 45, 0, 273, 100,0 }, - {3795,3795, 33, 0, 326, 106,0 }, - {3796,3796, 56, 0, 506, 200,0 }, - {3796,3796, 51, 0, 506, 200,0 }, - {3797,3797, 44, 0, 126, 66,0 }, - {3798,3798, 44, 0, 553, 186,0 }, - {3534,3534, 56, 0, 240, 100,0 }, - { 158, 158, 68, 0, 126, 140,0 }, - {3799,3799, 51, 0, 513, 206,0 }, - {3800,3800, 46, 0, 506, 200,0 }, - {3801,3801, 44, 0, 513, 206,0 }, - {3802,3802, 44, 0, 3720, 1260,0 }, - { 152, 152, 45, 0, 220, 80,0 }, - {3803,3803, 0, 0, 40000, 86,0 }, - {3804,3804, 0, 0, 40000, 226,0 }, - {3805,3805, 0, 0, 40000, 73,0 }, - {3806,3806, 0, 0, 40000, 73,0 }, - {3807,3807, 0, 0, 40000, 93,0 }, - {3808,3808, 0, 0, 4653, 660,0 }, - {3809,3809, 0, 0, 6686, 2246,0 }, - {3810,3810, 0, 0, 1180, 413,0 }, - {3811,3811, 0, 0, 966, 293,0 }, - {3812,3812, 0, 0, 1780, 66,0 }, - {3780,3780, 45, 0, 5900, 113,0 }, - {3061,3061, 45, 0, 40000, 0,0 }, - {3813,3813, 60, 0, 126, 226,0 }, - {3781,3781, 60, 0, 93, 0,0 }, - {3814,3814, 44, 0, 393, 86,0 }, - {3815,3815, 57, 0, 166, 80,0 }, - {3816,3816, 56, 0, 240, 100,0 }, - {3817,3817, 60, 0, 113, 0,0 }, - {3818,3818, 60, 0, 113, 0,0 }, - {3517,3517, 45, 0, 213, 213,0 }, - {3819,3819, 0, 0, 4033, 100,0 }, - {3820,3820, 0, 0, 5200, 873,0 }, - {3821,3821, 0, 0, 40000, 0,0 }, - {3822,3822, 0, 0, 10493, 160,0 }, - {3823,3823, 0, 0, 40000, 740,0 }, - {3824,3825, 0, 1, 40000, 366,0.078125 }, - {3826,3826, 0, 0, 40000, 5100,0 }, - {3827,3827, 0, 0, 40000, 766,0 }, - {3828,1172, 0, 1, 40000, 780,0.15625 }, - {3829,3829, 0, 0, 40000, 60,0 }, - {3830,3830, 0, 0, 566, 133,0 }, - {3831,3831, 32, 0, 146, 0,0 }, - {3832,3832, 36, 0, 273, 0,0 }, - {3833,3833, 88, 0, 340, 120,0 }, - {3834,3834, 0, 0, 9006, 240,0 }, - {3835,3835, 0, 0, 9206, 246,0 }, - {3836,3836, 0, 0, 9246, 386,0 }, - {3837,3837, 0, 0, 9440, 220,0 }, - {3838,3838, 0, 0, 8900, 133,0 }, - {3839,3839, 0, 0, 9400, 253,0 }, - {3840,3840, 0, 0, 4613, 420,0 }, - {3841,3841, 0, 0, 9233, 426,0 }, - {3842,3842, 0, 0, 40000, 526,0 }, - {3843,3843, 0, 0, 40000, 640,0 }, - {3844,3844, 0, 0, 40000, 666,0 }, - {3845,3845, 0, 0, 40000, 1053,0 }, - {3846,3846, 0, 0, 40000, 173,0 }, - {3847,3847, 0, 0, 40000, 246,0 }, - {3848,3848, 0, 0, 40000, 226,0 }, - {3849,3849, 0, 0, 4073, 233,0 }, - {3850,3850, 0, 0, 14286, 326,0 }, - {3851,3851, 0, 0, 9233, 146,0 }, - {3852,3852, 0, 0, 4480, 133,0 }, - {3853,3853, 0, 0, 40000, 53,0 }, - {3854,3854, 0, 0, 40000, 126,0 }, - {3855,3855, 0, 0, 40000, 126,0 }, - {3856,3856, 0, 0, 18226, 146,0 }, - {3857,3857, 0, 0, 40000, 326,0 }, - {3858,3858, 0, 0, 40000, 0,0 }, - {3859,3859, 0, 0, 40000, 300,0 }, - {3860,3860, 0, 0, 40000, 0,0 }, - {3861,3861, 0, 0, 40000, 0,0 }, - {3862,3862, 0, 0, 40000, 0,0 }, - {3863,3863, 0, 0, 40000, 140,0 }, - {3864,3864, 0, 0, 40000, 153,0 }, - {3865,3865, 0, 0, 40000, 233,0 }, - {3866,3866, 0, 0, 40000, 186,0 }, - {3867,3867, 0, 0, 40000, 413,0 }, - {3868,3868, 0, 0, 40000, 373,0 }, - {3869,3869, 0, 0, 1246, 440,0 }, - {3870,3870, 0, 0, 4620, 1513,0 }, - {3871,3871, 0, 0, 40000, 433,0 }, - {3872,3872, 0, 0, 40000, 453,0 }, - {3873,3873, 0, 0, 40000, 1440,0 }, - {3874,3874, 0, 0, 40000, 480,0 }, - {3875,3875, 0, 0, 40000, 1360,0 }, - {3876,3876, 0, 0, 40000, 0,0 }, - {3877,3877, 0, 0, 40000, 353,0 }, - {3878,3878, 0, 0, 40000, 86,0 }, - {3879,3879, 0, 0, 40000, 126,0 }, - {3880,3880, 0, 0, 40000, 73,0 }, - {3881,3881, 0, 0, 40000, 80,0 }, - {3882,3882, 0, 0, 40000, 246,0 }, - {3883,3883, 0, 0, 40000, 93,0 }, - {3884,3884, 0, 0, 40000, 120,0 }, - {3885,3885, 0, 0, 40000, 180,0 }, - {3886,3886, 0, 0, 40000, 133,0 }, - {3887,3887, 0, 0, 40000, 133,0 }, - {3888,3888, 0, 0, 40000, 153,0 }, - {3889,3889, 0, 0, 40000, 93,0 }, - {3890,3890, 0, 0, 40000, 140,0 }, - {3891,3891, 0, 0, 40000, 100,0 }, - {3892,3892, 0, 0, 40000, 146,0 }, - {3893,3893, 0, 0, 40000, 126,0 }, - {3894,3894, 0, 0, 40000, 160,0 }, - {3895,3895, 0, 0, 40000, 226,0 }, - {3896,3896, 0, 0, 40000, 140,0 }, - {3897,3897, 0, 0, 40000, 200,0 }, - {3898,3898, 0, 0, 40000, 66,0 }, - {3899,3899, 0, 0, 40000, 446,0 }, - {3900,3900, 0, 0, 40000, 140,0 }, - {3901,3901, 0, 0, 40000, 400,0 }, - {3902,3902, 0, 0, 40000, 373,0 }, - {3903,3903, 0, 0, 40000, 1306,0 }, - {3904,3904, 0, 0, 40000, 186,0 }, - {3905,3905, 0, 0, 40000, 640,0 }, - {3906,3906, 0, 0, 40000, 346,0 }, - {3907,3907, 0, 0, 40000, 140,0 }, - {3908,3908, 0, 0, 40000, 253,0 }, - {3909,3909, 0, 0, 8980, 746,0 }, - {3910,3910, 0, 0, 40000, 1266,0 }, - {3911,3911, 0, 0, 40000, 1306,0 }, - {3912,3912, 0, 0, 7226, 593,0 }, - {3913,3913, 0, 0, 40000, 140,0 }, - {3914,3914, 0, 0, 40000, 220,0 }, - {3915,3915, 0, 0, 40000, 146,0 }, - {3916,3916, 0, 0, 4606, 1506,0 }, - {3917,3917, 0, 0, 40000, 80,0 }, - {3918,3918, 0, 0, 40000, 0,0 }, - {3919,3919, 0, 0, 40000, 0,0 }, - {3920,3920, 0, 0, 613, 226,0 }, - {3921,3921, 0, 0, 9073, 2946,0 }, - {3922,3922, 0, 0, 40000, 73,0 }, - {3923,3923, 0, 0, 3726, 200,0 }, - {3924,3924, 0, 0, 3680, 373,0 }, - {3925,3925, 0, 0, 7113, 186,0 }, - {3926,3926, 0, 0, 2406, 106,0 }, - {3927,3927, 0, 0, 40000, 0,0 }, - {3928,3928, 0, 0, 40000, 253,0 }, - {3929,3929, 0, 0, 40000, 0,0 }, - {3930,3930, 0, 0, 40000, 80,0 }, - {3931,3931, 0, 0, 40000, 86,0 }, - {3932,3932, 0, 0, 18186, 740,0 }, - {3933,3933, 0, 0, 18426, 813,0 }, - { 523, 523, 0, 0, 200, 260,0 }, - {3934,3934, 0, 0, 340, 146,0 }, - {3935,3935, 0, 0, 366, 260,0 }, - {3936,3936, 48, 0, 126, 0,0 }, - {3937,3937, 27, 0, 200, 106,0 }, - {3938,3938, 40, 0, 1073, 800,0 }, - {3939,3939, 48, 0, 100, 0,0 }, - {3938,3938, 45, 0, 933, 666,0 }, - {3940,3940, 48, 0, 140, 333,0 }, - {3938,3938, 47, 0, 933, 666,0 }, - {3941,3941, 48, 0, 1840, 0,0 }, - {3938,3938, 49, 0, 953, 686,0 }, - {3938,3938, 53, 0, 906, 686,0 }, - {3938,3938, 56, 0, 913, 693,0 }, - { 129, 129, 52, 0, 293, 126,0 }, - { 130, 130, 48, 0, 173, 93,0 }, - { 129, 129, 58, 0, 286, 126,0 }, - { 132, 132, 47, 0, 173, 100,0 }, - { 492, 492, 43, 0, 820, 306,0 }, - { 132, 132, 49, 0, 173, 93,0 }, - { 132, 132, 51, 0, 173, 93,0 }, - { 132, 132, 54, 0, 173, 93,0 }, - { 132, 132, 57, 0, 146, 86,0 }, - { 492, 492, 72, 0, 706, 300,0 }, - { 137, 137, 76, 0, 1900, 666,0 }, - { 138, 138, 84, 0, 740, 300,0 }, - { 139, 139, 36, 0, 353, 146,0 }, - { 140, 140, 76, 0, 1886, 680,0 }, - { 141, 141, 84, 0, 220, 113,0 }, - { 135, 135, 83, 0, 1353, 480,0 }, - { 142, 142, 84, 0, 386, 160,0 }, - {3942,3942, 24, 0, 2313, 780,0 }, - { 137, 137, 77, 0, 1893, 660,0 }, - { 144, 144, 60, 0, 213, 0,0 }, - { 145, 145, 65, 0, 180, 146,0 }, - { 146, 146, 59, 0, 173, 93,0 }, - { 147, 147, 51, 0, 266, 213,0 }, - { 148, 148, 45, 0, 513, 200,0 }, - { 149, 149, 71, 0, 246, 26,0 }, - { 150, 150, 60, 0, 500, 193,0 }, - { 151, 151, 58, 0, 513, 200,0 }, - { 152, 152, 53, 0, 220, 86,0 }, - { 153, 153, 64, 0, 113, 40,0 }, - { 154, 154, 71, 0, 840, 300,0 }, - { 156, 156, 61, 0, 166, 80,0 }, - { 158, 158, 48, 0, 173, 213,0 }, - { 159, 159, 69, 0, 126, 140,0 }, - { 160, 160, 68, 0, 126, 140,0 }, - { 161, 161, 63, 0, 326, 113,0 }, - { 162, 162, 74, 0, 860, 286,0 }, - { 163, 163, 60, 0, 386, 160,0 }, - { 164, 164, 80, 0, 1106, 273,0 }, - { 165, 165, 64, 0, 126, 66,0 }, - { 166, 166, 69, 0, 386, 80,0 }, - { 167, 167, 73, 0, 546, 306,0 }, - { 168, 168, 75, 0, 126, 140,0 }, - { 169, 169, 68, 0, 340, 320,0 }, - { 131, 131, 48, 0, 520, 200,0 }, - {3061,3061, 53, 0, 40000, 0,0 }, - {3943,3944, 0, 4, 2153, 0,0 }, - {3945,3946, 0, 4, 9060, 393,0 }, - { 174,3947, 0, 4, 6953, 0,0 }, - {3948,3949, 0, 4, 9386, 140,0 }, - { 9,3950, 0, 4, 1626, 426,0 }, - {3951,3952, 0, 4, 18466, 240,0 }, - {3953,3954, 0, 4, 4666, 1486,0 }, - { 15,3955, 0, 4, 5700, 1986,0 }, - {3956,3957, 0, 4, 40000, 100,0 }, - {3958,3959, 0, 4, 40000, 73,0 }, - {3960,3961, 0, 4, 40000, 73,0 }, - {3962,3963, 0, 4, 40000, 73,0 }, - {3964,3965, 0, 4, 18280, 153,0 }, - {3966,3965, 0, 4, 18686, 160,0 }, - { 31,3967, 0, 4, 40000, 0,0 }, - {3968,3969, 0, 4, 17966, 100,0 }, - {3970,3971, 0, 4, 40000, 66,0 }, - {3972,3971, 0, 4, 40000, 66,0 }, - {3973,3974, 0, 4, 40000, 46,0 }, - {3975,3976, 0, 4, 18693, 106,0 }, - {3977,3976, 0, 4, 18593, 106,0 }, - {3978,3979, 0, 4, 9366, 106,0 }, - {3980,3981, 0, 4, 9120, 226,0 }, - {3982,3983, 0, 4, 40000, 140,0 }, - {3984,3985, 0, 4, 40000, 800,0 }, - { 54,3986, 0, 4, 2520, 706,0 }, - {3987,3988, 0, 4, 40000, 86,0 }, - {3989,3990, 0, 4, 40000, 233,0 }, - {3991, 253, 0, 4, 40000, 66,0 }, - {3992,3992, 0, 0, 40000, 0,0 }, - {3993,3993, 0, 0, 40000, 120,0 }, - {3994,3995, 0, 4, 40000, 80,0 }, - {3996,3997, 0, 4, 40000, 73,0 }, - {3998,3999, 0, 4, 40000, 86,0 }, - {1503,4000, 0, 4, 40000, 93,0 }, - { 88,4001, 0, 4, 40000, 1220,0 }, - {3743,4002, 0, 4, 7706, 1260,0 }, - { 92,4003, 0, 4, 40000, 186,0 }, - { 93,4004, 0, 4, 40000, 813,0 }, - { 94,4005, 0, 4, 7720, 1260,0 }, - { 96,4006, 0, 4, 40000, 2460,0 }, - { 103,4007, 0, 4, 3720, 1240,0 }, - { 104,4008, 0, 4, 3020, 1226,0 }, - { 105,4009, 0, 4, 6086, 2453,0 }, - { 107,4010, 0, 4, 2100, 760,0 }, - { 108,4011, 0, 4, 40000, 73,0 }, - { 110,4012, 0, 4, 40000, 100,0 }, - { 111,4013, 0, 4, 2366, 820,0 }, - {4014,4015, 0, 4, 1026, 326,0 }, - { 115,4016, 0, 4, 1853, 0,0 }, - { 118,4017, 0, 4, 1553, 53,0 }, - { 119,4018, 0, 4, 593, 0,0 }, - { 120,4019, 0, 4, 2293, 1173,0 }, - { 121,4020, 0, 4, 10673, 3000,0 }, - { 123,4021, 0, 4, 7413, 2486,0 }, - { 124,4022, 0, 4, 40000, 1126,0 }, - { 125,4023, 0, 4, 40000, 1546,0 }, - {4024,4024, 35, 0, 706, 266,0 }, - {4025,4026, 38, 1, 273, 106,0 }, - {4027,4028, 38, 1, 366, 133,0 }, - {4029,4030, 48, 1, 280, 133,-1.90625 }, - {4031,4031, 51, 0, 113, 80,0 }, - {4032,4033, 48, 1, 953, 346,-1.90625 }, - {4034,4034, 61, 1, 3200, 540,0.09375 }, - {3369,1557, 70, 4, 833, 0,0 }, - {4035,4036, 79, 1, 1306, 513,0.078125 }, - {4037,4037, 62, 0, 5200, 466,0 }, - {4038,4039, 67, 1, 2153, 1080,0.078125 }, - {4040,4040, 62, 1, 3226, 573,0.09375 }, - {4041,4042, 54, 1, 286, 133,0 }, - {4041,4043, 48, 1, 286, 126,0 }, - { 389, 389, 42, 0, 266, 73,0 }, - {4044,4045, 48, 1, 280, 126,0 }, - {4046,4047, 48, 1, 380, 60,0 }, - {4048,4048, 16, 0, 180, 20,0 }, - {4049,4049, 16, 0, 740, 20,0 }, - {4050,4051, 64, 4, 1366, 0,0 }, - { 844, 844,244, 2, 6, 0,0 }, - { 855, 855,244, 2, 6, 0,0 }, - { 880, 880,232, 0, 253, 80,0 }, - { 882, 882,220, 0, 40000, 266,0 }, - { 887, 887, 35, 0, 133, 46,0 }, - { 884, 884, 35, 0, 233, 80,0 }, - { 885, 885, 35, 0, 226, 86,0 }, - { 886, 886, 35, 0, 113, 0,0 }, - { 361, 361, 35, 0, 286, 73,0 }, - { 767, 767, 35, 0, 3020, 786,0 }, - { 888, 888, 35, 0, 246, 53,0 }, - {2141,2141, 35, 0, 186, 73,0 }, - { 891, 891, 35, 0, 713, 266,0 }, - {2142,2142, 35, 0, 200, 100,0 }, - {2143,2143, 35, 0, 220, 80,0 }, - {2144,2144, 35, 0, 2393, 100,0 }, - {2145,2145, 35, 0, 1980, 813,0 }, - { 376, 376, 35, 0, 1880, 840,0 }, - { 895, 895, 35, 0, 366, 140,0 }, - {2146,2146, 35, 0, 346, 106,0 }, - { 382, 382, 35, 0, 1073, 113,0 }, - {2147,2147, 35, 0, 106, 80,0 }, - { 898, 898, 35, 0, 206, 153,0 }, - { 899, 899, 35, 0, 633, 240,0 }, - { 900, 900, 35, 0, 620, 240,0 }, - { 871, 871, 35, 0, 380, 73,0 }, - { 388, 388, 35, 0, 286, 80,0 }, - { 901, 901, 35, 0, 260, 26,0 }, - { 902, 902, 35, 0, 1093, 73,0 }, - { 903, 903, 35, 0, 126, 73,0 }, - {3500,3500, 35, 2, 6, 0,0 }, - {4052,4052, 0, 0, 14166, 320,0 }, - {4053,4053, 0, 0, 7413, 653,0 }, - {4054,4054, 0, 0, 40000, 146,0 }, - {4055,4055, 0, 0, 40000, 113,0 }, - {4056,4056, 0, 0, 16773, 193,0 }, - {4057,4057, 0, 0, 40000, 73,0 }, - {4058,4058, 0, 0, 40000, 0,0 }, - {4059,4059, 0, 0, 966, 373,0 }, - {4060,4060, 0, 0, 40000, 80,0 }, - {4061,4061, 0, 0, 40000, 80,0 }, - {4062,4062, 0, 0, 18473, 93,0 }, - {4063,4063, 0, 0, 40000, 60,0 }, - {4064,4064, 0, 0, 40000, 73,0 }, - {4065,4065, 0, 0, 40000, 0,0 }, - {4066,4066, 0, 0, 40000, 213,0 }, - {4067,4067, 0, 0, 40000, 66,0 }, - {4068,4068, 0, 0, 1413, 1026,0 }, - {4069,4069, 0, 0, 506, 200,0 }, - {4070,4070, 0, 0, 3793, 1106,0 }, - {4071,4071, 0, 0, 40000, 220,0 }, - {4072,4072, 0, 0, 40000, 46,0 }, - {4073,4073, 0, 0, 40000, 0,0 }, - {4074,4074, 0, 0, 40000, 60,0 }, - {4075,4075, 0, 0, 40000, 0,0 }, - {4076,4076, 0, 0, 40000, 33,0 }, - {4077,4077, 0, 0, 40000, 0,0 }, - {4078,4078, 0, 0, 40000, 146,0 }, - {4079,4079, 0, 0, 40000, 66,0 }, - {4080,4080, 0, 0, 40000, 353,0 }, - {4081,4081, 0, 0, 40000, 66,0 }, - {4082,4082, 0, 0, 40000, 53,0 }, - {4083,4083, 0, 0, 40000, 73,0 }, - {4084,4084, 0, 0, 40000, 66,0 }, - {4085,4085, 0, 0, 40000, 926,0 }, - {4086,4086, 0, 0, 2833, 200,0 }, - { 127, 127, 36, 0, 386, 166,0 }, - {4087,4087, 36, 0, 100, 0,0 }, - {2030,2030, 36, 0, 346, 140,0 }, - {3782,3782, 48, 0, 93, 0,0 }, - {3783,3783, 36, 0, 146, 0,0 }, - {4088,4088, 48, 0, 1886, 653,0 }, - { 132, 132, 69, 0, 126, 66,0 }, - {4088,4088, 52, 0, 1853, 626,0 }, - { 152, 152, 48, 0, 220, 86,0 }, - {4088,4088, 55, 0, 1886, 640,0 }, - { 139, 139, 57, 0, 293, 133,0 }, - {4088,4088, 58, 0, 1860, 633,0 }, - {4088,4088, 60, 0, 1886, 633,0 }, - {4089,4089, 62, 0, 2660, 900,0 }, - {4088,4088, 63, 0, 1880, 646,0 }, - { 134, 134, 70, 0, 966, 360,0 }, - {4090,4090, 70, 0, 973, 346,0 }, - {4091,4091, 53, 0, 1866, 640,0 }, - {3516,3516, 48, 0, 180, 93,0 }, - {4092,4092, 84, 0, 1360, 473,0 }, - {4093,4093, 43, 0, 513, 206,0 }, - {4094,4094, 56, 0, 1353, 480,0 }, - {3791,3791, 24, 0, 1866, 613,0 }, - { 134, 134, 65, 0, 1346, 486,0 }, - { 146, 146, 48, 0, 173, 93,0 }, - { 146, 146, 54, 0, 173, 93,0 }, - {4095,4095, 42, 0, 246, 140,0 }, - {4095,4095, 39, 0, 240, 133,0 }, - {3816,3816, 52, 0, 306, 113,0 }, - {4096,4096, 52, 0, 413, 86,0 }, - { 158, 158, 60, 0, 146, 166,0 }, - { 158, 158, 66, 0, 146, 166,0 }, - { 158, 158, 59, 0, 146, 166,0 }, - {3538,3538, 91, 0, 773, 233,0 }, - {3547,3547,109, 0, 5300, 1786,0 }, - {4097,4097, 79, 0, 560, 313,0 }, - {4098,4098, 0, 0, 10646, 73,0 }, - {4099,4100, 0, 1, 14166, 586,0.03125 }, - {4101,4102, 0, 1, 15553, 546,0.03125 }, - {4103,4104, 0, 1, 11746, 320,0.046875 }, - {4105,4106, 0, 1, 14706, 646,0.15625 }, - {4107,4108, 0, 1, 7320, 100,0.046875 }, - {4109,4110, 0, 1, 40000, 0,0.0625 }, - {4111,4112, 0, 1, 13660, 260,0 }, - {4113,4114, 0, 1, 15026, 133,0 }, - {4115,4116, 0, 1, 40000, 0,2.5e-05 }, - {4117,4118, 0, 1, 4980, 3400,0 }, - {4119,4120, 0, 1, 7840, 2660,0.046875 }, - {4121,4122, 0, 1, 8326, 180,0 }, - {4123,4124, 0, 1, 1093, 140,0 }, - {4125,4126, 0, 1, 2280, 400,0 }, - {4127,4128, 0, 1, 4553, 1486,0.03125 }, - {4129,4129, 0, 1, 40000, 0,0.03125 }, - {4130,4131, 0, 1, 40000, 60,0.15625 }, - {4132,4133, 0, 1, 40000, 93,0.078125 }, - {4134,4135, 0, 1, 40000, 86,0.15625 }, - {4136,4137, 0, 1, 40000, 520,0.03125 }, - {4138,4139, 0, 1, 40000, 140,0.0625 }, - {4140,4141, 0, 1, 40000, 133,0.140625 }, - {4142,4143, 0, 1, 40000, 73,0 }, - {4144,4145, 0, 1, 40000, 346,0.109375 }, - {4146,4147, 0, 1, 3693, 86,0 }, - {4148,4149, 0, 1, 6586, 460,2.5e-05 }, - {4150,4151, 0, 1, 4320, 93,0 }, - {4152,4153, 0, 1, 7346, 126,0.046875 }, - {4154,4155, 0, 1, 3633, 260,0 }, - {4156,4157, 0, 1, 40000, 126,-1.95312 }, - {4158,4159, 0, 1, 40000, 126,-1.9375 }, - {4160,4161, 0, 1, 40000, 46,0.234375 }, - {4162,4163, 0, 1, 40000, 0,0.03125 }, - {4164,4165, 0, 1, 10320, 86,0 }, - {4166,4167, 0, 1, 12933, 133,0 }, - {4168,4169, 0, 1, 11820, 240,0.046875 }, - {4170,4171, 0, 1, 3966, 166,0 }, - {4172,4173, 0, 1, 40000, 0,0 }, - {4174,4174, 0, 0, 2666, 160,0 }, - {4175,4176, 0, 1, 15046, 93,0.078125 }, - {4177,4178, 0, 1, 40000, 100,0 }, - {4179,4179, 0, 0, 40000, 260,0 }, - {4180,4181, 0, 1, 40000, 126,2.5e-05 }, - {4182,4182, 0, 0, 40000, 233,0 }, - {4183,4184, 0, 1, 40000, 440,0.078125 }, - {4185,4186, 0, 1, 2160, 606,0.109375 }, - {4187,4188, 0, 1, 14753, 2400,0.03125 }, - {4189,4190, 0, 1, 7680, 646,0.03125 }, - {4191,4192, 0, 1, 40000, 446,0.0625 }, - {4193,4194, 0, 1, 40000, 866,-0.0625 }, - {4195,4195, 0, 1, 40000, 1220,0.078125 }, - {4196,4196, 0, 1, 40000, 1960,0.0625 }, - {4197,4198, 0, 1, 40000, 433,0.125 }, - {4199,4200, 0, 1, 40000, 140,0.140625 }, - {4201,4202, 0, 1, 40000, 806,0.109375 }, - {4203,4204, 0, 1, 2040, 486,0.125 }, - {4205,4206, 0, 1, 40000, 86,0 }, - {4207,4208, 0, 1, 40000, 80,0.03125 }, - {4209,4209, 0, 0, 40000, 73,0 }, - {4210,4210, 0, 0, 40000, 126,0 }, - {4211,4212, 0, 1, 40000, 400,0.0625 }, - {4213,4214, 0, 1, 40000, 120,0.0625 }, - {4215,4216, 0, 1, 40000, 0,0.09375 }, - {4217,4217, 0, 1, 40000, 0,0.125 }, - {4218,4219, 0, 1, 40000, 186,0 }, - {4220,4220, 0, 0, 40000, 166,0 }, - {4221,4221, 0, 0, 40000, 73,0 }, - {4222,4222, 0, 0, 40000, 60,0 }, - {4223,4224, 0, 1, 40000, 140,0 }, - {4225,4225, 0, 0, 40000, 140,0 }, - {4226,4226, 0, 0, 40000, 66,0 }, - {4227,4228, 0, 1, 40000, 133,0 }, - {4229,4229, 0, 0, 40000, 86,0 }, - {4230,4230, 0, 0, 40000, 73,0 }, - {4231,4231, 0, 0, 40000, 106,0 }, - {4232,4233, 0, 1, 40000, 186,0.03125 }, - {4234,4235, 0, 1, 40000, 86,0.046875 }, - {4236,4237, 0, 1, 40000, 0,0.03125 }, - {4238,4238, 0, 0, 40000, 300,0 }, - {4239,4239, 0, 0, 40000, 66,0 }, - {4240,4241, 0, 1, 40000, 73,0.125 }, - {4242,4243, 0, 1, 40000, 86,0.109375 }, - {4244,4245, 0, 1, 40000, 146,0.109375 }, - {4246,4247, 0, 1, 40000, 66,-0.03125 }, - {4248,4248, 0, 0, 40000, 60,0 }, - {4249,4250, 0, 1, 40000, 213,0.15625 }, - {4251,4252, 0, 1, 40000, 66,0.125 }, - {4253,4254, 0, 1, 40000, 100,0.03125 }, - {4255,4256, 0, 1, 40000, 1513,0.078125 }, - {4257,4258, 0, 1, 40000, 353,0.109375 }, - {4259,4260, 0, 1, 40000, 133,0.078125 }, - {4261,4262, 0, 1, 40000, 746,0.140625 }, - {4263,4264, 0, 1, 40000, 0,0.109375 }, - {4265,4266, 0, 1, 5033, 1606,0.0625 }, - {4267,4268, 0, 1, 40000, 1146,0.09375 }, - {4269,4270, 0, 1, 40000, 1586,0.109375 }, - {4271,4272, 0, 1, 40000, 0,0.09375 }, - {4273,4274, 0, 1, 40000, 1006,0.125 }, - {4275,4275, 0, 1, 2680, 793,0.109375 }, - {4276,4277, 0, 1, 40000, 0,-0.046875 }, - {4278,4279, 0, 1, 9000, 3186,0.125 }, - {4280,4281, 0, 1, 40000, 1073,-0.078125 }, - {4282,4283, 0, 1, 40000, 2093,0.140625 }, - {4284,4285, 0, 1, 40000, 0,0.078125 }, - {4286,4287, 0, 1, 9580, 713,0.03125 }, - {4288,4289, 0, 1, 6286, 380,0 }, - {4290,4291, 0, 1, 2220, 426,0.03125 }, - {4292,4292, 0, 0, 1166, 760,0 }, - {4293,4294, 0, 1, 1186, 240,0 }, - {4295,4296, 0, 1, 40000, 100,0.0625 }, - {4297,4297, 0, 0, 40000, 160,0 }, - {4298,4298, 0, 0, 40000, 120,0 }, - {4299,4299, 0, 0, 8673, 2413,0 }, - {4300,4300, 0, 0, 393, 126,0 }, - {4301,4302, 0, 1, 1220, 393,0.03125 }, - {4303,4303, 0, 0, 246, 93,0 }, - {4304,4305, 0, 1, 1953, 393,0 }, - {4306,4307, 0, 1, 566, 146,0 }, - {4308,4309, 0, 1, 4220, 133,0 }, - {4310,4311, 0, 1, 2873, 73,0.109375 }, - {4312,4312, 0, 0, 613, 60,0 }, - {4313,4314, 0, 1, 40000, 186,0 }, - {4315,4316, 0, 1, 11880, 2993,0 }, - {4317,4317, 0, 0, 1573, 86,0 }, - {4318,4319, 0, 1, 40000, 793,0 }, - {4320,4321, 0, 1, 40000, 173,0 }, - {4322,4323, 0, 1, 40000, 793,0 }, - {4324,4324, 0, 0, 606, 133,0 }, - {4325,4325, 34, 0, 133, 40,0 }, - {4326,4326, 28, 0, 193, 46,0 }, - {4327,4328, 39, 1, 553, 126,0 }, - {4327,4328, 33, 1, 553, 126,0 }, - {4329,4330, 63, 1, 160, 80,0 }, - {4331,4331, 15, 0, 113, 0,0 }, - {4332,4332, 36, 0, 106, 0,0 }, - {4332,4333, 36, 1, 480, 173,0.40625 }, - {4334,4335, 25, 1, 313, 153,0 }, - {4336,4335, 25, 1, 206, 100,0 }, - {4337,4338, 61, 1, 153, 93,0 }, - {4339,4340, 38, 1, 340, 133,0 }, - {4341,4342, 37, 1, 206, 93,0 }, - {4343,4344, 15, 1, 346, 153,0 }, - {4345,4346,100, 1, 146, 0,0.140625 }, - {4347,4348, 19, 1, 553, 200,0 }, - {4349,4349, 48, 0, 180, 86,0 }, - {4350,4351, 15, 1, 333, 153,0 }, - {4352,4353, 12, 1, 340, 146,0 }, - {4354,4355, 11, 1, 346, 146,0 }, - {4356,4357, 61, 1, 2706, 1033,0.09375 }, - {4358,4355, 8, 1, 340, 146,0 }, - {4359,4360, 91, 1, 1166, 366,-0.046875 }, - {4361,4361, 70, 0, 966, 346,0 }, - {4362,4363, 80, 1, 300, 93,0.125 }, - {4364,4364, 58, 0, 206, 53,0 }, - {4365,4357, 62, 1, 2333, 820,0.09375 }, - {4366,4367, 31, 1, 773, 200,0 }, - {4368,4360, 91, 1, 1160, 360,-0.03125 }, - {4369,4370, 41, 1, 373, 113,0 }, - {4371,4372, 35, 1, 406, 126,0 }, - {4373,4374, 29, 1, 146, 106,0 }, - {4375,4376, 41, 1, 400, 126,0 }, - {4375,4376, 37, 1, 400, 126,0 }, - {4377,4378, 54, 1, 286, 133,0 }, - {4377,4379, 48, 1, 286, 126,0 }, - {4380,4381, 77, 1, 193, 93,0 }, - {4382,4383, 72, 1, 200, 93,0 }, - {4384,4384, 40, 0, 513, 0,0 }, - {4385,4385, 38, 0, 200, 20,0 }, - {4386,4386, 36, 0, 620, 20,0 }, - {4387,4388, 60, 1, 120, 80,0 }, - {4388,4389, 60, 1, 380, 80,0 }, - {4390,4390, 73, 0, 166, 33,0 }, - {4391,4392, 68, 1, 153, 40,0 }, - {4393,4394, 18, 1, 200, 80,0 }, - {4395,4396, 18, 1, 253, 73,0 }, - {4397,4397, 90, 0, 193, 20,0 }, - {4398,4398, 90, 0, 793, 40,0 }, - {4399,4400, 64, 1, 373, 73,0.03125 }, - {4401,4402, 80, 1, 406, 153,0.03125 }, - {4403,4404, 64, 1, 1866, 606,0 }, - {4405,4405, 67, 0, 106, 26,0 }, - {4406,4407, 50, 1, 173, 0,0 }, - {4408,4408, 36, 0, 4646, 0,0 }, - {4409,4409, 0, 0, 40000, 86,0 }, - {4410,4410, 0, 0, 40000, 73,0 }, - {4411,4411, 0, 0, 2433, 700,0 }, - {4412,4412, 0, 0, 1233, 26,0 }, - {4413,4413, 0, 0, 40000, 66,0 }, - {4414,4414, 0, 0, 40000, 60,0 }, - {4415,4415, 0, 0, 40000, 60,0 }, - {4416,4416, 0, 0, 40000, 66,0 }, - {4417,4417, 0, 0, 40000, 66,0 }, - {4418,4418, 0, 0, 40000, 0,0 }, - {4418,4418, 73, 0, 40000, 0,0 }, - {4419,4419, 0, 0, 40000, 60,0 }, - {4420,4420, 0, 0, 40000, 60,0 }, - {4421,4421, 0, 0, 7326, 2486,0 }, - {4422,4422, 0, 0, 4886, 1586,0 }, - {4423,4423, 0, 0, 646, 20,0 }, - {4424,4424, 0, 0, 253, 20,0 }, - {4424,4424, 12, 0, 253, 20,0 }, - {4425,4425, 0, 0, 640, 100,0 }, - {4425,4425, 1, 0, 640, 106,0 }, - {4426,4426, 0, 0, 133, 106,0 }, - {4426,4426, 23, 0, 133, 106,0 }, - {4427,4427, 0, 0, 653, 100,0 }, - {4428,4428, 0, 0, 4166, 1546,0 }, - {4429,4429, 0, 0, 40000, 73,0 }, - {4430,4430, 0, 0, 40000, 60,0 }, - {4431,4431, 0, 0, 40000, 53,0 }, - {4432,4432, 0, 0, 40000, 0,0 }, - {4433,4433, 0, 0, 246, 20,0 }, - {4434,4434, 0, 2, 6, 0,0 }, - {4435,4435, 0, 0, 4946, 233,0 }, - {4436,4436, 0, 0, 4946, 233,0 }, - {4437,4437, 0, 0, 4953, 240,0 }, - {4438,4438, 0, 0, 4946, 233,0 }, - {4439,4439, 0, 0, 18233, 46,0 }, - {4440,4440, 0, 0, 2386, 26,0 }, - {4441,4441, 0, 0, 4640, 633,0 }, - {4442,4442, 0, 0, 18466, 100,0 }, - {4443,4443, 0, 0, 18440, 66,-2 }, - {4444,4444, 0, 0, 18440, 6140,-2 }, - {4445,4445, 0, 0, 1206, 433,-2 }, - {4446,4446, 0, 0, 4626, 240,0 }, - {4447,4447, 0, 0, 726, 400,0 }, - {4448,4448, 0, 0, 5866, 73,0 }, - {4449,4449, 0, 0, 40000, 73,0 }, - {4450,4450, 0, 0, 40000, 73,0 }, - {4451,4451, 0, 0, 40000, 73,0 }, - {4452,4452, 0, 0, 40000, 73,0 }, - {4453,4453, 0, 0, 6500, 346,0 }, - {4454,4454, 0, 0, 6506, 346,0 }, - {4455,4455, 0, 0, 40000, 66,-2 }, - {4456,4456, 0, 0, 40000, 66,-2 }, - {4457,4457, 0, 0, 40000, 0,0 }, - {4458,4458, 0, 0, 40000, 46,0 }, - {4459,4459, 0, 0, 40000, 0,0 }, - {4459,4459, 0, 0, 40000, 0,-2 }, - {4460,4460, 0, 0, 2386, 26,0 }, - {4461,4461, 0, 0, 40000, 73,-2 }, - {4462,4462, 0, 0, 5866, 26,-2 }, - {4463,4463, 0, 0, 40000, 133,0 }, - {4464,4464, 0, 0, 40000, 133,0 }, - {4465,4465, 0, 0, 40000, 126,0 }, - {4466,4466, 0, 0, 253, 20,0 }, - {4467,4467, 0, 0, 8866, 1366,0 }, - {4468,4468, 0, 0, 1040, 766,0 }, - {4469,4469, 0, 0, 40000, 146,-2 }, - {4470,4470, 0, 0, 40000, 153,-2 }, - {4471,4471, 0, 0, 40000, 466,-2 }, - {4472,4472, 0, 0, 40000, 66,0 }, - {4473,4473, 0, 0, 2333, 566,0 }, - {4474,4474, 0, 0, 40000, 140,-2 }, - {4475,4475, 0, 0, 40000, 100,-2 }, - {4476,4476, 0, 0, 40000, 226,-2 }, - {4477,4477, 0, 0, 40000, 0,0 }, - {3712,3712, 0, 0, 40000, 226,-2 }, - {4478,4478, 0, 0, 40000, 140,-2 }, - {4479,4479, 0, 0, 40000, 66,0 }, - {4480,4480, 0, 0, 40000, 73,0 }, - {4481,4481, 0, 0, 40000, 73,0 }, - {4482,4482, 0, 0, 40000, 86,-2 }, - {4483,4483, 0, 0, 40000, 80,0 }, - {4484,4484, 0, 0, 40000, 73,-2 }, - {4485,4485, 0, 0, 40000, 80,-2 }, - {4486,4486, 0, 0, 40000, 73,-2 }, - {4487,4487, 0, 0, 40000, 73,0 }, - {4488,4488, 0, 0, 40000, 73,0 }, - {4489,4489, 0, 0, 40000, 93,0 }, - {4490,4490, 0, 0, 40000, 73,0 }, - {4491,4491, 0, 0, 11946, 13,0 }, - {4492,4492, 0, 0, 40000, 73,0 }, - {4462,4462, 0, 0, 5866, 26,0 }, - {4493,4493, 0, 0, 40000, 820,0 }, - {4494,4494, 0, 0, 2153, 873,0 }, - {1221,1221, 0, 0, 40000, 293,0.171875 }, - {4495,4495, 0, 0, 1620, 120,0 }, - {4496,4496, 0, 0, 15120, 93,0 }, - {4497,4497, 0, 0, 14613, 93,0 }, - {4498,4498, 0, 0, 2346, 793,0 }, - {4499,4499, 0, 0, 40000, 2380,0 }, - {4500,4500, 0, 0, 40000, 1280,0 }, - {4501,4501, 0, 0, 40000, 1460,0 }, - {4502,4502, 0, 0, 40000, 2513,0 }, - {4503,4503, 0, 0, 14840, 1266,0 }, - {4504,4504, 0, 0, 4513, 640,0 }, - {4505,4505, 0, 0, 4680, 806,0 }, - {4506,4506, 0, 0, 40000, 100,0 }, - {4507,4507, 0, 0, 40000, 66,0 }, - {4508,4508, 0, 0, 2420, 413,0 }, - {4509,4509, 0, 0, 406, 73,-2 }, - {4510,4510, 0, 0, 1166, 400,0 }, - {4511,4511, 0, 0, 1213, 106,0 }, - {4512,4512, 0, 0, 273, 60,-2 }, - {4513,4513, 0, 0, 40000, 2380,0 }, - {4514,4514, 0, 0, 40000, 440,0 }, - {1261,1261, 0, 0, 40000, 2960,0 }, - {4515,4515, 37, 0, 973, 73,-2 }, - {4516,4516, 48, 0, 106, 0,-2 }, - {4517,4517, 48, 0, 286, 133,-2 }, - {4518,4518, 62, 0, 166, 60,0 }, - {4519,4519, 44, 0, 980, 360,0 }, - {4520,4520, 80, 0, 100, 0,0 }, - {4519,4519, 50, 0, 980, 346,0 }, - {4521,4521, 48, 0, 106, 0,-2 }, - {4519,4519, 55, 0, 973, 360,0 }, - {4522,4522, 61, 0, 513, 20,0 }, - {4519,4519, 58, 0, 966, 353,0 }, - {4519,4519, 63, 0, 973, 353,0 }, - {4523,4523, 71, 0, 1366, 580,0 }, - {4519,4519, 72, 0, 820, 306,0 }, - {4524,4524, 70, 0, 1886, 666,0 }, - {4523,4523, 88, 0, 1353, 560,0 }, - {4525,4525, 76, 0, 1873, 653,0 }, - {4526,4526, 84, 0, 260, 113,0 }, - {4523,4523, 68, 0, 1366, 553,0 }, - {4527,4527, 72, 0, 153, 53,0 }, - {4528,4528, 28, 0, 1193, 413,0 }, - {4524,4524, 81, 0, 1353, 480,0 }, - {4529,4529, 58, 0, 246, 120,-2 }, - {4529,4529, 55, 0, 246, 120,-2 }, - {4529,4529, 44, 0, 246, 120,-2 }, - {4529,4529, 49, 0, 246, 120,-2 }, - {4529,4529, 40, 0, 286, 133,-2 }, - {4530,4530, 55, 0, 740, 560,-2 }, - {4530,4530, 48, 0, 893, 693,-2 }, - {4531,4531, 52, 0, 513, 206,0 }, - {4531,4531, 45, 0, 513, 206,0 }, - {4532,4532, 48, 0, 173, 100,-2 }, - {4533,4533, 48, 0, 120, 266,-2 }, - {4534,4534, 48, 0, 253, 60,-2 }, - {4509,4509, 73, 0, 160, 20,-2 }, - {4509,4509, 68, 0, 160, 20,-2 }, - {4509,4509, 63, 0, 193, 20,-2 }, - {4535,4535,108, 0, 406, 26,0 }, - {4536,4536,108, 0, 740, 26,0 }, + { 0, 0, 0, 0, 9006, 133, 0, 0 }, + { 1, 1, 0, 0, 9206, 146, 0, 0 }, + { 2, 2, 0, 0, 9246, 240, 0, 0 }, + { 3, 3, 0, 0, 9440, 140, 0, 0 }, + { 4, 4, 0, 0, 8900, 120, 0, 0 }, + { 5, 5, 0, 0, 9400, 140, 0, 0 }, + { 6, 6, 0, 0, 7460, 380, 0, 0 }, + { 7, 7, 0, 0, 9226, 93, 0, 0 }, + { 8, 8, 0, 0, 4613, 420, 0, 0 }, + { 9, 9, 0, 0, 7286, 4713, 0, 0 }, + { 10, 10, 0, 0, 2280, 746, 0, 0 }, + { 11, 11, 0, 0, 9233, 240, 0, 0 }, + { 12, 12, 0, 0, 346, 153, 0, 0 }, + { 13, 13, 0, 0, 633, 233, 0, 0 }, + { 14, 14, 0, 0, 4660, 1573, 0, 0 }, + { 15, 15, 0, 0, 1166, 400, 0, 0 }, + { 16, 16, 0, 0, 40000, 126, 0, 0 }, + { 17, 17, 0, 0, 40000, 93, 0, 0 }, + { 18, 18, 0, 0, 40000, 93, 0, 0 }, + { 19, 19, 0, 0, 40000, 553, 0, 0 }, + { 20, 20, 0, 0, 40000, 660, 0, 0 }, + { 21, 21, 0, 0, 40000, 73, 0, 0 }, + { 22, 22, 0, 0, 40000, 146, 0, 0 }, + { 23, 23, 0, 0, 40000, 146, 0, 0 }, + { 24, 24, 0, 0, 4026, 100, 0, 0 }, + { 25, 25, 0, 0, 14286, 120, 0, 0 }, + { 26, 26, 0, 0, 9233, 106, 0, 0 }, + { 27, 27, 0, 0, 4480, 100, 0, 0 }, + { 28, 28, 0, 0, 40000, 60, 0, 0 }, + { 29, 29, 0, 0, 40000, 80, 0, 0 }, + { 30, 30, 0, 0, 40000, 80, 0, 0 }, + { 31, 31, 0, 0, 18226, 100, 0, 0 }, + { 32, 32, 0, 0, 40000, 0, 0, 0 }, + { 33, 33, 0, 0, 40000, 80, 0, 0 }, + { 34, 34, 0, 0, 40000, 0, 0, 0 }, + { 35, 35, 0, 0, 40000, 53, 0, 0 }, + { 36, 36, 0, 0, 40000, 0, 0, 0 }, + { 37, 37, 0, 0, 40000, 0, 0, 0 }, + { 38, 38, 0, 0, 40000, 0, 0, 0 }, + { 39, 39, 0, 0, 40000, 160, 0, 0 }, + { 40, 40, 0, 0, 40000, 233, 0, 0 }, + { 41, 41, 0, 0, 40000, 73, 0, 0 }, + { 42, 42, 0, 0, 40000, 233, 0, 0 }, + { 43, 43, 0, 0, 40000, 213, 0, 0 }, + { 44, 44, 0, 0, 1246, 453, 0, 0 }, + { 45, 45, 0, 0, 4580, 786, 0, 0 }, + { 46, 46, 0, 0, 6873, 1246, 0, 0 }, + { 47, 47, 0, 0, 40000, 100, 0, 0 }, + { 48, 48, 0, 0, 40000, 140, 0, 0 }, + { 49, 49, 0, 0, 40000, 393, 0, 0 }, + { 50, 50, 0, 0, 40000, 406, 0, 0 }, + { 51, 51, 0, 0, 40000, 373, 0, 0 }, + { 52, 52, 0, 0, 40000, 0, 0, 0 }, + { 53, 53, 0, 0, 40000, 360, 0, 0 }, + { 54, 54, 0, 0, 1060, 380, 0, 0 }, + { 55, 55, 0, 0, 40000, 80, 0, 0 }, + { 56, 56, 0, 0, 40000, 73, 0, 0 }, + { 57, 57, 0, 0, 40000, 66, 0, 0 }, + { 58, 58, 0, 0, 40000, 60, 0, 0 }, + { 59, 59, 0, 0, 40000, 73, 0, 0 }, + { 60, 60, 0, 0, 40000, 66, 0, 0 }, + { 61, 61, 0, 0, 40000, 86, 0, 0 }, + { 62, 62, 0, 0, 40000, 66, 0, 0 }, + { 63, 63, 0, 0, 40000, 73, 0, 0 }, + { 64, 64, 0, 0, 40000, 80, 0, 0 }, + { 65, 65, 0, 0, 40000, 80, 0, 0 }, + { 66, 66, 0, 0, 40000, 73, 0, 0 }, + { 67, 67, 0, 0, 40000, 73, 0, 0 }, + { 68, 68, 0, 0, 40000, 53, 0, 0 }, + { 69, 69, 0, 0, 40000, 73, 0, 0 }, + { 70, 70, 0, 0, 40000, 126, 0, 0 }, + { 71, 71, 0, 0, 40000, 73, 0, 0 }, + { 72, 72, 0, 0, 40000, 73, 0, 0 }, + { 73, 73, 0, 0, 40000, 73, 0, 0 }, + { 74, 74, 0, 0, 40000, 66, 0, 0 }, + { 75, 75, 0, 0, 40000, 153, 0, 0 }, + { 76, 76, 0, 0, 40000, 153, 0, 0 }, + { 77, 77, 0, 0, 40000, 146, 0, 0 }, + { 78, 78, 0, 0, 40000, 146, 0, 0 }, + { 79, 79, 0, 0, 40000, 66, 0, 0 }, + { 80, 80, 0, 0, 40000, 60, 0, 0 }, + { 81, 81, 0, 0, 40000, 86, 0, 0 }, + { 82, 82, 0, 0, 40000, 73, 0, 0 }, + { 83, 83, 0, 0, 40000, 66, 0, 0 }, + { 84, 84, 0, 0, 40000, 153, 0, 0 }, + { 85, 85, 0, 0, 40000, 233, 0, 0 }, + { 86, 86, 0, 0, 40000, 80, 0, 0 }, + { 87, 87, 0, 0, 40000, 400, 0, 0 }, + { 88, 88, 0, 0, 40000, 1373, 0, 0 }, + { 89, 89, 0, 0, 40000, 193, 0, 0 }, + { 90, 90, 0, 0, 40000, 1273, 0, 0 }, + { 91, 91, 0, 0, 40000, 186, 0, 0 }, + { 92, 92, 0, 0, 40000, 86, 0, 0 }, + { 93, 93, 0, 0, 40000, 286, 0, 0 }, + { 94, 94, 0, 0, 40000, 140, 0, 0 }, + { 95, 95, 0, 0, 7440, 2473, 0, 0 }, + { 96, 96, 0, 0, 40000, 1220, 0, 0 }, + { 97, 97, 0, 0, 4946, 2713, 0, 0 }, + { 98, 98, 0, 0, 40000, 160, 0, 0 }, + { 99, 99, 0, 0, 8966, 406, 0, 0 }, + { 100, 100, 0, 0, 40000, 1353, 0, 0 }, + { 101, 101, 0, 0, 40000, 1306, 0, 0 }, + { 102, 102, 0, 0, 40000, 933, 0, 0 }, + { 103, 103, 0, 0, 9086, 226, 0, 0 }, + { 104, 104, 0, 0, 7233, 326, 0, 0 }, + { 105, 105, 0, 0, 7286, 200, 0, 0 }, + { 106, 106, 0, 0, 14180, 4406, 0, 0 }, + { 107, 107, 0, 0, 1180, 406, 0, 0 }, + { 108, 108, 0, 0, 40000, 66, 0, 0 }, + { 109, 109, 0, 0, 40000, 213, 0, 0 }, + { 110, 110, 0, 0, 40000, 73, 0, 0 }, + { 111, 111, 0, 0, 4606, 413, 0, 0 }, + { 112, 112, 0, 0, 613, 240, 0, 0 }, + { 113, 113, 0, 0, 1166, 400, 0, 0 }, + { 114, 114, 0, 0, 200, 353, 0, 0 }, + { 115, 115, 0, 0, 4553, 1480, 0, 0 }, + { 116, 116, 0, 0, 3740, 1260, 0, 0 }, + { 117, 117, 0, 0, 7240, 2300, 0, 0 }, + { 118, 118, 0, 0, 3020, 73, 0, 0 }, + { 119, 119, 0, 0, 1626, 800, 0, 0 }, + { 120, 120, 0, 0, 2466, 620, 0, 0 }, + { 121, 121, 0, 0, 12053, 3160, 0, 0 }, + { 122, 122, 0, 0, 466, 120, 0, 0 }, + { 123, 123, 0, 0, 1000, 320, 0, 0 }, + { 124, 124, 0, 0, 380, 60, 0, 0 }, + { 125, 125, 0, 0, 40000, 200, 0, 0 }, + { 126, 126, 0, 0, 560, 86, 0, 0 }, + { 127, 127, 35, 0, 386, 160, 0, 0 }, + { 128, 128, 52, 0, 126, 26, 0, 0 }, + { 129, 129, 48, 0, 286, 126, 0, 0 }, + { 130, 130, 58, 0, 173, 93, 0, 0 }, + { 129, 129, 60, 0, 286, 126, 0, 0 }, + { 131, 131, 47, 0, 520, 200, 0, 0 }, + { 132, 132, 43, 0, 173, 93, 0, 0 }, + { 131, 131, 49, 0, 520, 200, 0, 0 }, + { 133, 133, 43, 0, 160, 80, 0, 0 }, + { 131, 131, 51, 0, 526, 206, 0, 0 }, + { 134, 134, 43, 0, 1860, 653, 0, 0 }, + { 131, 131, 54, 0, 520, 200, 0, 0 }, + { 131, 131, 57, 0, 520, 200, 0, 0 }, + { 135, 135, 72, 0, 1860, 633, 0, 0 }, + { 131, 131, 60, 0, 506, 200, 0, 0 }, + { 136, 136, 76, 0, 1566, 546, 0, 0 }, + { 137, 137, 84, 0, 1340, 466, 0, 0 }, + { 138, 138, 36, 0, 1220, 433, 0, 0 }, + { 139, 139, 65, 0, 293, 133, 0, 0 }, + { 140, 140, 84, 0, 1333, 460, 0, 0 }, + { 141, 141, 83, 0, 220, 113, 0, 0 }, + { 135, 135, 84, 0, 1366, 473, 0, 0 }, + { 142, 142, 24, 0, 1893, 633, 0, 0 }, + { 136, 136, 77, 0, 1586, 553, 0, 0 }, + { 143, 143, 60, 0, 173, 93, 0, 0 }, + { 144, 144, 65, 0, 213, 126, 0, 0 }, + { 145, 145, 59, 0, 173, 140, 0, 0 }, + { 146, 146, 51, 0, 173, 100, 0, 0 }, + { 147, 147, 45, 0, 260, 206, 0, 0 }, + { 148, 148, 71, 0, 433, 180, 0, 0 }, + { 149, 149, 60, 0, 280, 26, 0, 0 }, + { 150, 150, 58, 0, 500, 186, 0, 0 }, + { 151, 151, 53, 0, 513, 200, 0, 0 }, + { 152, 152, 64, 0, 220, 86, 0, 0 }, + { 153, 153, 71, 0, 106, 46, 0, 0 }, + { 154, 154, 61, 0, 993, 340, 0, 0 }, + { 155, 155, 61, 0, 1906, 640, 0, 0 }, + { 156, 156, 44, 0, 206, 86, 0, 0 }, + { 157, 157, 40, 0, 586, 140, 0, 0 }, + { 158, 158, 69, 0, 126, 140, 0, 0 }, + { 159, 159, 68, 0, 126, 140, 0, 0 }, + { 160, 160, 63, 0, 146, 166, 0, 0 }, + { 161, 161, 74, 0, 280, 100, 0, 0 }, + { 162, 162, 60, 0, 1026, 320, 0, 0 }, + { 163, 163, 80, 0, 226, 100, 0, 0 }, + { 164, 164, 64, 0, 2713, 913, 0, 0 }, + { 165, 165, 72, 0, 120, 66, 0, 0 }, + { 166, 166, 73, 0, 386, 80, 0, 0 }, + { 167, 167, 70, 0, 553, 306, 0, 0 }, + { 168, 168, 68, 0, 126, 140, 0, 0 }, + { 169, 169, 48, 0, 386, 373, 0, 0 }, + { 131, 131, 53, 0, 520, 206, 0, 0 }, + { 170, 170, 0, 0, 40000, 0, 0, 0 }, + { 171, 171, 0, 0, 40000, 73, 0, 0 }, + { 172, 173, 0, 4, 5886, 100, 0, 0 }, + { 174, 175, 0, 4, 6913, 93, 0, 0 }, + { 176, 177, 0, 4, 4873, 120, 0, 0 }, + { 178, 178, 0, 0, 40000, 0, 0, 0 }, + { 179, 180, 0, 4, 4626, 433, 0, 0 }, + { 181, 181, 0, 0, 2280, 746, 0, 0 }, + { 182, 182, 0, 0, 40000, 0, 0, 0 }, + { 183, 184, 0, 4, 620, 233, 0, 0 }, + { 185, 186, 0, 4, 4626, 1546, 0, 0 }, + { 187, 187, 0, 0, 1166, 400, 0, 0 }, + { 188, 189, 0, 4, 40000, 60, 0, 0 }, + { 190, 191, 0, 4, 40000, 60, 0, 0 }, + { 192, 193, 0, 4, 40000, 73, 0, 0 }, + { 194, 194, 0, 0, 40000, 73, 0, 0 }, + { 195, 196, 0, 4, 40000, 66, 0, 0 }, + { 197, 198, 0, 4, 40000, 86, 0, 0 }, + { 199, 200, 0, 4, 40000, 66, 0, 0 }, + { 201, 202, 0, 4, 3713, 100, 0, 0 }, + { 203, 204, 0, 4, 14686, 126, 0, 0 }, + { 205, 206, 0, 4, 9233, 153, 0, 0 }, + { 207, 208, 0, 4, 14640, 133, 0, 0 }, + { 209, 210, 0, 4, 4626, 106, 0, 0 }, + { 211, 212, 0, 4, 40000, 66, 0, 0 }, + { 213, 213, 0, 0, 40000, 73, 0, 0 }, + { 214, 215, 0, 4, 620, 100, 0, 0 }, + { 216, 217, 0, 4, 4060, 100, 0, 0 }, + { 218, 219, 0, 4, 14513, 193, 0, 0 }, + { 220, 221, 0, 4, 2813, 106, 0, 0 }, + { 222, 223, 0, 4, 493, 153, 0, 0 }, + { 224, 224, 0, 0, 40000, 0, 0, 0 }, + { 225, 226, 0, 4, 7993, 93, 0, 0 }, + { 227, 227, 0, 0, 40000, 0, 0, 0 }, + { 228, 228, 0, 0, 40000, 133, 0, 0 }, + { 229, 230, 0, 4, 713, 213, 0, 0 }, + { 231, 232, 0, 4, 40000, 146, 0, 0 }, + { 233, 234, 0, 4, 40000, 0, 0, 0 }, + { 235, 236, 0, 4, 993, 340, 0, 0 }, + { 235, 237, 0, 4, 3260, 1120, 0, 0 }, + { 46, 238, 0, 4, 6720, 1246, 0, 0 }, + { 239, 240, 0, 4, 40000, 140, 0, 0 }, + { 241, 242, 0, 4, 40000, 146, 0, 0 }, + { 243, 243, 0, 0, 40000, 100, 0, 0 }, + { 244, 244, 0, 0, 40000, 60, 0, 0 }, + { 245, 245, 0, 0, 40000, 73, 0, 0 }, + { 246, 247, 0, 4, 720, 106, 0, 0 }, + { 248, 249, 0, 4, 40000, 126, 0, 0 }, + { 250, 250, 0, 0, 40000, 0, 0, 0 }, + { 251, 251, 0, 0, 40000, 126, 0, 0 }, + { 252, 253, 0, 4, 40000, 66, 0, 0 }, + { 254, 255, 0, 4, 40000, 93, 0, 0 }, + { 256, 257, 0, 4, 40000, 73, 0, 0 }, + { 258, 259, 0, 4, 40000, 86, 0, 0 }, + { 260, 261, 0, 4, 40000, 93, 0, 0 }, + { 262, 263, 0, 4, 40000, 80, 0, 0 }, + { 264, 265, 0, 4, 40000, 200, 0, 0 }, + { 266, 267, 0, 4, 40000, 73, 0, 0 }, + { 268, 269, 0, 4, 40000, 80, 0, 0 }, + { 270, 271, 0, 4, 40000, 73, 0, 0 }, + { 272, 273, 0, 4, 40000, 126, 0, 0 }, + { 274, 275, 0, 4, 40000, 100, 0, 0 }, + { 276, 276, 0, 0, 40000, 113, 0, 0 }, + { 277, 278, 0, 4, 40000, 186, 0, 0 }, + { 279, 280, 0, 4, 40000, 160, 0, 0 }, + { 281, 282, 0, 4, 40000, 206, 0, 0 }, + { 283, 283, 0, 0, 40000, 80, 0, 0 }, + { 284, 285, 0, 4, 40000, 73, 0, 0 }, + { 286, 287, 0, 4, 40000, 73, 0, 0 }, + { 288, 288, 0, 0, 40000, 93, 0, 0 }, + { 289, 290, 0, 4, 40000, 66, 0, 0 }, + { 291, 292, 0, 4, 40000, 153, 0, 0 }, + { 293, 294, 0, 4, 40000, 153, 0, 0 }, + { 295, 296, 0, 4, 40000, 320, 0, 0 }, + { 88, 297, 0, 4, 40000, 1280, 0, 0 }, + { 298, 299, 0, 4, 40000, 266, 0, 0 }, + { 300, 301, 0, 4, 40000, 1180, 0, 0 }, + { 302, 302, 0, 0, 40000, 286, 0, 0 }, + { 303, 303, 0, 0, 40000, 140, 0, 0 }, + { 304, 304, 0, 0, 13246, 2473, 0, 0 }, + { 305, 306, 0, 4, 40000, 1073, 0, 0 }, + { 307, 307, 0, 0, 9233, 240, 0, 0 }, + { 308, 308, 0, 0, 1186, 406, 0, 0 }, + { 309, 309, 0, 0, 40000, 1306, 0, 0 }, + { 310, 310, 0, 0, 40000, 933, 0, 0 }, + { 311, 312, 0, 4, 9100, 240, 0, 0 }, + { 313, 314, 0, 4, 7280, 326, 0, 0 }, + { 315, 316, 0, 4, 3553, 326, 0, 0 }, + { 317, 318, 0, 4, 6966, 2206, 0, 0 }, + { 107, 319, 0, 4, 1160, 406, 0, 0 }, + { 108, 320, 0, 4, 40000, 66, 0, 0 }, + { 109, 321, 0, 4, 720, 213, 0, 0 }, + { 322, 323, 0, 4, 40000, 73, 0, 0 }, + { 324, 325, 0, 4, 613, 246, 0, 0 }, + { 326, 327, 0, 4, 1206, 386, 0, 0 }, + { 328, 328, 0, 0, 173, 106, 0, 0 }, + { 329, 329, 0, 0, 966, 333, 0, 0 }, + { 330, 331, 0, 4, 1906, 320, 0, 0 }, + { 332, 332, 0, 0, 3120, 73, 0, 0 }, + { 333, 333, 0, 0, 226, 73, 0, 0 }, + { 334, 334, 0, 0, 6600, 806, 0, 0 }, + { 335, 335, 0, 0, 273, 60, 0, 0 }, + { 336, 336, 0, 0, 12053, 660, 0, 0 }, + { 337, 337, 0, 0, 40000, 240, 0, 0 }, + { 338, 339, 0, 6, 6, 0, 0, 0 }, + { 340, 341, 0, 4, 560, 73, 0, 0 }, + { 342, 342, 35, 0, 40000, 0, 0, 0 }, + { 343, 343, 0, 0, 180, 100, 0, 0 }, + { 344, 344, 35, 0, 340, 146, 0, 0 }, + { 345, 345, 35, 0, 213, 33, 0, 0 }, + { 346, 346, 50, 0, 306, 20, 0, 0 }, + { 347, 347, 18, 0, 420, 146, 0, 0 }, + { 348, 348, 72, 0, 173, 86, 0, 0 }, + { 349, 349, 74, 0, 160, 93, 0, 0 }, + { 350, 350, 35, 0, 380, 146, 0, 0 }, + { 351, 351, 16, 0, 1206, 420, 0, 0 }, + { 352, 352, 0, 2, 6, 0, 0, 0 }, + { 353, 353, 38, 0, 200, 106, 0, 0 }, + { 354, 354, 38, 0, 346, 146, 0, 0 }, + { 355, 355, 31, 0, 406, 20, 0, 0 }, + { 355, 355, 35, 0, 406, 66, 0, 0 }, + { 355, 355, 38, 0, 406, 66, 0, 0 }, + { 355, 355, 41, 0, 406, 66, 0, 0 }, + { 355, 355, 45, 0, 306, 73, 0, 0 }, + { 355, 355, 50, 0, 306, 73, 0, 0 }, + { 356, 356, 36, 0, 1373, 493, 0, 0 }, + { 357, 357, 36, 0, 146, 33, 0, 0 }, + { 358, 358, 48, 0, 213, 86, 0, 0 }, + { 358, 358, 36, 0, 246, 86, 0, 0 }, + { 359, 359, 36, 0, 113, 53, 0, 0 }, + { 360, 360, 0, 0, 133, 40, 0, 0 }, + { 361, 361, 61, 0, 180, 26, 0, 0 }, + { 362, 362, 96, 0, 706, 266, 0, 0 }, + { 363, 363, 38, 0, 520, 193, 0, 0 }, + { 127, 127, 16, 0, 620, 233, 0, 0 }, + { 364, 365, 18, 4, 200, 26, 0, 0 }, + { 366, 366, 30, 0, 406, 246, 0, 0 }, + { 367, 368, 35, 4, 200, 100, 0, 0 }, + { 129, 129, 0, 0, 353, 153, 0, 0 }, + { 369, 369, 0, 0, 213, 13, 0, 0 }, + { 370, 370, 88, 0, 333, 113, 0, 0 }, + { 371, 371, 88, 0, 140, 73, 0, 0 }, + { 372, 372, 79, 0, 2540, 1040, 0, 0 }, + { 135, 135, 14, 0, 9213, 3066, 0, 0 }, + { 373, 373, 46, 0, 1093, 60, 0, 0 }, + { 374, 375,129, 4, 1193, 433, 0, 0 }, + { 376, 376, 58, 0, 1600, 726, 0, 0 }, + { 377, 377,164, 0, 526, 820, 0, 0 }, + { 378, 378,142, 0, 9153, 3073, 0, 0 }, + { 379, 379, 9, 0, 200, 100, 0, 0 }, + { 380, 381, 35, 4, 2340, 806, 0, 0 }, + { 382, 382, 28, 0, 1060, 120, 0, 0 }, + { 383, 383, 46, 0, 953, 20, 0, 0 }, + { 384, 384, 60, 0, 440, 160, 0, 0 }, + { 384, 384, 54, 0, 513, 180, 0, 0 }, + { 385, 385, 72, 0, 253, 120, 0, 0 }, + { 385, 385, 67, 0, 253, 113, 0, 0 }, + { 385, 385, 60, 0, 253, 106, 0, 0 }, + { 386, 386, 1, 0, 966, 613, 0, 0 }, + { 387, 387, 77, 0, 340, 86, 0, 0 }, + { 387, 387, 72, 0, 340, 86, 0, 0 }, + { 388, 388, 90, 0, 213, 86, 0, 0 }, + { 389, 389, 39, 0, 266, 73, 0, 0 }, + { 390, 390, 36, 0, 593, 73, 0, 0 }, + { 391, 392, 35, 4, 173, 46, 0, 0 }, + { 391, 393, 35, 4, 460, 66, 0, 0 }, + { 394, 394, 60, 0, 173, 20, 0, 0 }, + { 328, 328, 7, 0, 173, 106, 0, 0 }, + { 395, 395, 90, 0, 193, 20, 0, 0 }, + { 396, 396, 90, 0, 793, 40, 0, 0 }, + { 397, 397, 35, 0, 253, 86, 0, 0 }, + { 398, 399, 5, 4, 1913, 226, 0, 0 }, + { 400, 400,103, 0, 713, 273, 0, 0 }, + { 401, 401, 3, 0, 100, 26, 0, 0 }, + { 169, 169, 1, 0, 466, 413, 0, 0 }, + { 131, 131, 0, 0, 613, 226, 0, 0 }, + { 402, 402, 36, 0, 273, 53, 0, 0 }, + { 403, 403, 60, 0, 40000, 73, 0, 0 }, + { 404, 404, 37, 0, 1193, 426, 0, 0 }, + { 405, 405, 36, 0, 406, 20, 0, 0 }, + { 406, 406, 32, 0, 146, 73, 0, 0 }, + { 407, 407, 50, 0, 40000, 0, 0, 0 }, + { 408, 408, 50, 0, 793, 346, 0, 0 }, + { 409, 409, 83, 0, 120, 13, 0, 0 }, + { 410, 410, 72, 0, 433, 193, 0, 0 }, + { 148, 148, 59, 0, 513, 200, 0, 0 }, + { 411, 411, 64, 0, 173, 93, 0, 0 }, + { 411, 411, 60, 0, 173, 93, 0, 0 }, + { 412, 412, 72, 0, 160, 93, 0, 0 }, + { 412, 412, 62, 0, 173, 93, 0, 0 }, + { 413, 413, 83, 0, 773, 60, 0, 0 }, + { 414, 414, 0, 0, 40000, 80, 0, 0 }, + { 415, 415, 0, 0, 40000, 0, 0, 0 }, + { 416, 416, 0, 0, 40000, 73, 0, 0 }, + { 417, 417, 0, 0, 40000, 86, 0, 0 }, + { 418, 418, 0, 0, 40000, 0, 0, 0 }, + { 419, 419, 0, 0, 3440, 100, 0, 0 }, + { 420, 420, 0, 0, 3913, 420, 0, 0 }, + { 421, 421, 0, 0, 13620, 4640, 0, 0 }, + { 422, 422, 0, 0, 9233, 240, 0, 0 }, + { 423, 423, 0, 0, 633, 233, 0, 0 }, + { 424, 424, 0, 0, 4660, 1573, 0, 0 }, + { 425, 425, 0, 0, 4480, 1413, 0, 0 }, + { 426, 426, 0, 0, 40000, 0, 0, 0 }, + { 427, 427, 0, 0, 40000, 86, 0, 0 }, + { 428, 428, 60, 2, 6, 0, 0, 0 }, + { 429, 429, 73, 0, 593, 86, 0, 0 }, + { 429, 429, 74, 0, 593, 86, 0, 0 }, + { 429, 429, 80, 0, 593, 86, 0, 0 }, + { 429, 429, 84, 0, 593, 86, 0, 0 }, + { 429, 429, 92, 0, 520, 86, 0, 0 }, + { 430, 430, 81, 0, 786, 80, 0, 0 }, + { 430, 430, 83, 0, 786, 80, 0, 0 }, + { 430, 430, 95, 0, 680, 80, 0, 0 }, + { 431, 431, 35, 0, 593, 140, 0, 0 }, + { 432, 432, 60, 0, 213, 133, 0, 0 }, + { 357, 357, 59, 0, 113, 33, 0, 0 }, + { 432, 432, 44, 0, 213, 133, 0, 0 }, + { 433, 433, 41, 0, 713, 273, 0, 0 }, + { 434, 434, 97, 0, 113, 46, 0, 0 }, + { 433, 433, 44, 0, 513, 206, 0, 0 }, + { 433, 433, 48, 0, 506, 200, 0, 0 }, + { 435, 435, 96, 0, 700, 86, 0, 0 }, + { 433, 433, 51, 0, 520, 200, 0, 0 }, + { 433, 433, 54, 0, 513, 206, 0, 0 }, + { 436, 436, 40, 0, 1506, 793, 0, 0 }, + { 433, 433, 57, 0, 380, 160, 0, 0 }, + { 437, 437, 58, 0, 1600, 726, 0, 0 }, + { 438, 438, 97, 0, 233, 106, 0, 0 }, + { 439, 439, 50, 0, 186, 93, 0, 0 }, + { 437, 437, 60, 0, 1573, 713, 0, 0 }, + { 440, 440, 53, 0, 180, 73, 0, 0 }, + { 441, 441, 46, 0, 173, 126, 0, 0 }, + { 440, 440, 57, 0, 180, 40, 0, 0 }, + { 442, 442, 42, 0, 640, 240, 0, 0 }, + { 442, 442, 37, 0, 633, 233, 0, 0 }, + { 443, 443, 41, 0, 626, 240, 0, 0 }, + { 443, 443, 37, 0, 620, 233, 0, 0 }, + { 444, 444, 77, 0, 173, 40, 0, 0 }, + { 444, 444, 72, 0, 173, 40, 0, 0 }, + { 445, 445, 70, 0, 233, 100, 0, 0 }, + { 445, 445, 90, 0, 233, 93, 0, 0 }, + { 446, 446, 46, 0, 133, 73, 0, 0 }, + { 447, 447, 48, 0, 333, 73, 0, 0 }, + { 448, 448, 85, 0, 106, 33, 0, 0 }, + { 449, 449, 66, 0, 180, 26, 0, 0 }, + { 449, 449, 61, 0, 180, 26, 0, 0 }, + { 450, 450, 41, 0, 200, 66, 0, 0 }, + { 451, 451, 41, 0, 253, 66, 0, 0 }, + { 452, 452, 81, 0, 253, 26, 0, 0 }, + { 400, 400, 81, 0, 820, 306, 0, 0 }, + { 400, 400, 76, 0, 813, 300, 0, 0 }, + { 359, 359, 60, 0, 100, 40, 0, 0 }, + { 453, 453, 53, 0, 40000, 0, 0, 0 }, + { 454, 454, 0, 2, 6, 0, 0, 0 }, + { 455, 455, 0, 0, 200, 20, 0, 0 }, + { 456, 456, 0, 0, 4480, 100, 0, 0 }, + { 457, 457, 0, 0, 1180, 406, 0, 0 }, + { 458, 458, 0, 0, 40000, 86, 0, 0 }, + { 459, 459, 0, 0, 40000, 73, 0, 0 }, + { 460, 460, 0, 0, 3700, 66, 0, 0 }, + { 461, 461, 0, 0, 40000, 0, 0, 0 }, + { 462, 462, 0, 0, 6746, 2606, 0, 0 }, + { 463, 463, 0, 0, 40000, 213, 0, 0 }, + { 464, 464, 0, 0, 40000, 66, 0, 0 }, + { 465, 465, 0, 0, 40000, 100, 0, 0 }, + { 466, 466, 0, 0, 40000, 100, 0, 0 }, + { 467, 467, 0, 0, 5840, 806, 0, 0 }, + { 468, 468, 0, 0, 40000, 0, 0, 0 }, + { 469, 469, 0, 0, 40000, 0, 0, 0 }, + { 470, 470, 0, 0, 40000, 73, 0, 0 }, + { 471, 471, 0, 0, 40000, 133, 0, 0 }, + { 472, 472, 0, 0, 3320, 800, 0, 0 }, + { 473, 473, 0, 0, 40000, 173, 0, 0 }, + { 474, 474, 0, 0, 40000, 193, 0, 0 }, + { 475, 475, 0, 0, 2373, 800, 0, 0 }, + { 476, 476, 0, 0, 40000, 4986, 0, 0 }, + { 477, 477, 0, 0, 1180, 413, 0, 0 }, + { 478, 478, 0, 0, 3673, 1200, 0, 0 }, + { 479, 479, 0, 0, 973, 800, 0, 0 }, + { 480, 480, 0, 0, 7233, 2286, 0, 0 }, + { 481, 481, 0, 0, 40000, 73, 0, 0 }, + { 482, 482, 0, 0, 2526, 73, 0, 0 }, + { 483, 483, 0, 0, 393, 126, 0, 0 }, + { 484, 484, 0, 0, 40000, 200, 0, 0 }, + { 485, 485, 0, 0, 40000, 546, 0, 0 }, + { 486, 486, 0, 0, 1186, 413, 0, 0 }, + { 487, 487, 0, 0, 14166, 320, 0, 0 }, + { 488, 488, 0, 0, 8326, 646, 0, 0 }, + { 489, 489, 0, 0, 513, 206, 0, 0 }, + { 490, 490, 0, 0, 40000, 93, 0, 0 }, + { 491, 491, 50, 0, 1406, 353, 0, 0 }, + { 492, 492, 37, 0, 1040, 400, 0, 0 }, + { 493, 493, 39, 0, 406, 73, 0, 0 }, + { 494, 494, 39, 0, 3746, 860, 0, 0 }, + { 495, 495, 86, 0, 2133, 173, 0, 0 }, + { 496, 496, 43, 0, 140, 66, 0, 0 }, + { 127, 127, 24, 0, 513, 206, 0, 0 }, + { 127, 127, 29, 0, 520, 206, 0, 0 }, + { 497, 497, 50, 0, 340, 20, 0, 0 }, + { 498, 498, 30, 0, 5306, 1266, 0, 0 }, + { 498, 498, 33, 0, 3773, 886, 0, 0 }, + { 498, 498, 38, 0, 3746, 860, 0, 0 }, + { 498, 498, 42, 0, 3793, 906, 0, 0 }, + { 499, 499, 24, 0, 266, 160, 0, 0 }, + { 499, 499, 27, 0, 260, 153, 0, 0 }, + { 499, 499, 29, 0, 260, 153, 0, 0 }, + { 499, 499, 32, 0, 260, 153, 0, 0 }, + { 500, 500, 32, 0, 106, 26, 0, 0 }, + { 501, 501, 53, 0, 373, 186, 0, 0 }, + { 501, 501, 57, 0, 380, 193, 0, 0 }, + { 502, 502, 60, 0, 286, 133, 0, 0 }, + { 503, 503, 55, 0, 460, 126, 0, 0 }, + { 486, 486, 85, 0, 813, 293, 0, 0 }, + { 504, 504, 90, 0, 1580, 546, 0, 0 }, + { 505, 505, 84, 0, 246, 120, 0, 0 }, + { 506, 506, 48, 0, 826, 646, 0, 0 }, + { 507, 507, 48, 0, 266, 213, 0, 0 }, + { 132, 132, 72, 0, 126, 66, 0, 0 }, + { 508, 508, 72, 0, 106, 46, 0, 0 }, + { 509, 509, 72, 0, 100, 26, 0, 0 }, + { 510, 510, 63, 0, 1860, 633, 0, 0 }, + { 510, 510, 65, 0, 1853, 633, 0, 0 }, + { 511, 511, 79, 0, 1573, 553, 0, 0 }, + { 512, 512, 38, 0, 520, 793, 0, 0 }, + { 513, 513, 94, 0, 380, 160, 0, 0 }, + { 514, 514, 87, 0, 433, 306, 0, 0 }, + { 514, 514, 94, 0, 380, 273, 0, 0 }, + { 515, 515, 80, 0, 546, 273, 0, 0 }, + { 516, 516, 47, 0, 506, 200, 0, 0 }, + { 517, 517, 61, 0, 286, 133, 0, 0 }, + { 517, 517, 68, 0, 246, 120, 0, 0 }, + { 518, 518, 61, 0, 513, 206, 0, 0 }, + { 518, 518, 68, 0, 433, 180, 0, 0 }, + { 499, 499, 60, 0, 220, 133, 0, 0 }, + { 519, 519, 60, 0, 153, 46, 0, 0 }, + { 520, 520, 36, 0, 200, 20, 0, 0 }, + { 520, 520, 60, 0, 173, 20, 0, 0 }, + { 521, 521, 60, 0, 173, 20, 0, 0 }, + { 522, 522, 68, 0, 126, 26, 0, 0 }, + { 523, 523, 71, 0, 160, 186, 0, 0 }, + { 523, 523, 72, 0, 160, 186, 0, 0 }, + { 524, 524,101, 0, 966, 353, 0, 0 }, + { 525, 525, 36, 0, 3333, 480, 0, 0 }, + { 526, 526, 25, 0, 40000, 2293, 0, 0 }, + { 527, 527, 37, 0, 2106, 426, 0, 0 }, + { 528, 528, 36, 0, 720, 266, 0, 0 }, + { 528, 528, 41, 0, 713, 266, 0, 0 }, + { 529, 529, 84, 0, 173, 60, 0, 0 }, + { 530, 530, 54, 0, 40000, 0, 0, 0 }, + { 481, 481, 48, 0, 40000, 73, 0, 0 }, + { 531, 531, 0, 0, 10060, 1266, 0, 0 }, + { 532, 532, 0, 0, 4600, 606, 0, 0 }, + { 533, 533, 0, 0, 40000, 253, 0, 0 }, + { 534, 534, 0, 0, 40000, 73, 0, 0 }, + { 535, 535, 0, 0, 40000, 66, 0, 0 }, + { 536, 536, 0, 0, 40000, 80, 0, 0 }, + { 537, 537, 0, 0, 9413, 1393, 0, 0 }, + { 538, 538, 0, 0, 9000, 66, 0, 0 }, + { 539, 539, 0, 0, 40000, 0, 0, 0 }, + { 540, 540, 0, 0, 40000, 80, 0, 0 }, + { 541, 541, 0, 0, 40000, 120, 0, 0 }, + { 542, 542, 0, 0, 253, 73, 0, 0 }, + { 543, 543, 0, 0, 40000, 73, 0, 0 }, + { 544, 544, 0, 0, 18280, 800, 0, 0 }, + { 545, 545, 0, 0, 40000, 1133, 0, 0 }, + { 546, 546, 0, 0, 40000, 1226, 0, 0 }, + { 547, 547, 0, 0, 40000, 153, 0, 0 }, + { 135, 135, 49, 0, 3633, 1186, 0, 0 }, + { 548, 548, 35, 0, 2193, 80, 0, 0 }, + { 549, 549, 41, 0, 73, 26, 0, 0 }, + { 366, 366, 38, 0, 406, 246, 0, 0 }, + { 550, 550, 39, 0, 106, 20, 0, 0 }, + { 551, 551, 49, 0, 200, 133, 0, 0 }, + { 408, 408, 59, 0, 780, 326, 0, 0 }, + { 552, 552, 24, 0, 40000, 0, 0, 0 }, + { 552, 552, 27, 0, 40000, 0, 0, 0 }, + { 552, 552, 29, 0, 40000, 0, 0, 0 }, + { 552, 552, 32, 0, 40000, 0, 0, 0 }, + { 553, 553, 84, 0, 200, 33, 0, 0 }, + { 512, 512, 79, 0, 346, 460, 0, 0 }, + { 554, 554, 61, 0, 400, 126, 0, 0 }, + { 554, 554, 68, 0, 353, 120, 0, 0 }, + { 555, 555, 36, 0, 146, 86, 0, 0 }, + { 555, 555, 60, 0, 113, 53, 0, 0 }, + { 556, 556, 36, 0, 273, 53, 0, 0 }, + { 115, 115, 37, 0, 4580, 1513, 0, 0 }, + { 557, 557, 0, 0, 3806, 73, 0, 0 }, + { 558, 558, 0, 0, 40000, 0, 0, 0 }, + { 559, 559, 0, 0, 40000, 66, 0, 0 }, + { 560, 560, 0, 0, 5886, 133, 0, 0 }, + { 561, 561, 0, 0, 253, 26, 0, 0 }, + { 562, 562, 0, 0, 3246, 753, 0, 0 }, + { 563, 563, 0, 0, 40000, 100, 0, 0 }, + { 564, 564, 0, 0, 1620, 366, 0, 0 }, + { 565, 565, 0, 0, 40000, 0, 0, 0 }, + { 566, 566, 0, 0, 40000, 0, 0, 0 }, + { 567, 567, 0, 0, 40000, 0, 0, 0 }, + { 568, 568, 0, 0, 40000, 80, 0, 0 }, + { 569, 569, 0, 0, 760, 340, 0, 0 }, + { 570, 570, 0, 0, 40000, 0, 0, 0 }, + { 571, 571, 0, 0, 40000, 0, 0, 0 }, + { 572, 572, 0, 0, 40000, 0, 0, 0 }, + { 356, 356, 0, 0, 1893, 646, 0, 0 }, + { 573, 573, 0, 0, 40000, 93, 0, 0 }, + { 574, 574, 0, 0, 40000, 93, 0, 0 }, + { 575, 575, 0, 0, 40000, 200, 0, 0 }, + { 576, 576, 0, 0, 40000, 200, 0, 0 }, + { 577, 577, 0, 0, 40000, 126, 0, 0 }, + { 578, 578, 0, 0, 40000, 353, 0, 0 }, + { 579, 579, 0, 0, 40000, 346, 0, 0 }, + { 580, 580, 0, 0, 40000, 353, 0, 0 }, + { 581, 581, 0, 0, 40000, 100, 0, 0 }, + { 582, 582, 0, 0, 40000, 133, 0, 0 }, + { 583, 583, 0, 0, 2286, 713, 0, 0 }, + { 584, 584, 0, 0, 40000, 193, 0, 0 }, + { 585, 585, 0, 0, 40000, 0, 0, 0 }, + { 516, 516, 0, 0, 633, 240, 0, 0 }, + { 586, 586, 0, 0, 40000, 73, 0, 0 }, + { 587, 587, 0, 0, 40000, 73, 0, 0 }, + { 588, 588, 0, 0, 40000, 73, 0, 0 }, + { 498, 498, 26, 0, 5293, 1253, 0, 0 }, + { 494, 494, 35, 0, 3800, 913, 0, 0 }, + { 350, 350, 41, 0, 380, 153, 0, 0 }, + { 353, 353, 48, 0, 173, 100, 0, 0 }, + { 354, 354, 67, 0, 246, 120, 0, 0 }, + { 502, 502, 24, 0, 340, 146, 0, 0 }, + { 346, 346, 36, 0, 406, 73, 0, 0 }, + { 346, 346, 38, 0, 406, 20, 0, 0 }, + { 346, 346, 40, 0, 406, 73, 0, 0 }, + { 346, 346, 42, 0, 406, 20, 0, 0 }, + { 346, 346, 44, 0, 306, 20, 0, 0 }, + { 510, 510, 55, 0, 1866, 646, 0, 0 }, + { 346, 346, 46, 0, 306, 20, 0, 0 }, + { 136, 136, 80, 0, 1600, 573, 0, 0 }, + { 486, 486, 24, 0, 1193, 426, 0, 0 }, + { 153, 153, 50, 0, 106, 40, 0, 0 }, + { 346, 346, 24, 0, 540, 73, 0, 0 }, + { 516, 516, 31, 0, 626, 240, 0, 0 }, + { 498, 498, 35, 0, 3760, 880, 0, 0 }, + { 517, 517, 60, 0, 286, 133, 0, 0 }, + { 530, 530, 36, 0, 40000, 0, 0, 0 }, + { 530, 530, 48, 0, 40000, 0, 0, 0 }, + { 589, 589, 0, 0, 40000, 0, 0, 0 }, + { 139, 139, 76, 0, 253, 106, 0, 0 }, + { 156, 156, 48, 0, 206, 80, 0, 0 }, + { 157, 157, 48, 0, 426, 106, 0, 0 }, + { 165, 165, 69, 0, 120, 66, 0, 0 }, + { 167, 167, 75, 0, 546, 306, 0, 0 }, + { 590, 590, 0, 0, 40000, 0, 0, 0 }, + { 591, 591, 0, 0, 15486, 1580, 0, 0 }, + { 592, 592, 0, 0, 3446, 106, 0, 0 }, + { 593, 593, 0, 0, 1926, 146, 0, 0 }, + { 594, 594, 0, 0, 7293, 2380, 0, 0 }, + { 595, 595, 0, 0, 7613, 1566, 0, 0 }, + { 596, 596, 0, 0, 1153, 460, 0, 0 }, + { 597, 597, 0, 0, 1166, 400, 0, 0 }, + { 598, 598, 0, 0, 40000, 73, 0, 0 }, + { 599, 599, 0, 0, 40000, 766, 0, 0 }, + { 600, 600, 0, 0, 40000, 80, 0, 0 }, + { 601, 601, 0, 0, 1840, 513, 0, 0 }, + { 602, 602, 0, 0, 40000, 0, 0, 0 }, + { 603, 603, 0, 0, 4480, 733, 0, 0 }, + { 604, 604, 0, 0, 18226, 786, 0, 0 }, + { 605, 605, 0, 0, 4333, 233, 0, 0 }, + { 606, 606, 0, 0, 40000, 106, 0, 0 }, + { 607, 607, 0, 0, 40000, 366, 0, 0 }, + { 608, 608, 0, 0, 40000, 200, 0, 0 }, + { 609, 609, 0, 0, 713, 200, 0, 0 }, + { 610, 610, 0, 0, 8866, 1366, 0, 0 }, + { 611, 611, 0, 0, 2300, 73, 0, 0 }, + { 612, 612, 0, 0, 40000, 126, 0, 0 }, + { 613, 613, 0, 0, 40000, 1413, 0, 0 }, + { 614, 614, 0, 0, 40000, 333, 0, 0 }, + { 615, 615, 0, 0, 40000, 333, 0, 0 }, + { 616, 616, 0, 0, 40000, 26, 0, 0 }, + { 617, 617, 0, 0, 40000, 40, 0, 0 }, + { 618, 618, 0, 0, 4240, 353, 0, 0 }, + { 619, 619, 0, 0, 40000, 0, 0, 0 }, + { 620, 620, 0, 0, 40000, 73, 0, 0 }, + { 621, 621, 0, 0, 9020, 60, 0, 0 }, + { 622, 622, 0, 0, 3020, 0, 0, 0 }, + { 623, 623, 0, 0, 40000, 60, 0, 0 }, + { 624, 624, 0, 0, 40000, 73, 0, 0 }, + { 625, 625, 0, 0, 40000, 60, 0, 0 }, + { 626, 626, 0, 0, 40000, 53, 0, 0 }, + { 627, 627, 0, 0, 40000, 0, 0, 0 }, + { 628, 628, 0, 0, 40000, 66, 0, 0 }, + { 629, 629, 0, 0, 40000, 66, 0, 0 }, + { 630, 630, 0, 0, 5913, 426, 0, 0 }, + { 631, 631, 0, 0, 40000, 246, 0, 0 }, + { 632, 632, 0, 0, 40000, 206, 0, 0 }, + { 633, 633, 0, 0, 40000, 0, 0, 0 }, + { 634, 634, 0, 0, 2453, 780, 0, 0 }, + { 635, 635, 0, 0, 4740, 240, 0, 0 }, + { 636, 636, 0, 0, 1840, 353, 0, 0 }, + { 637, 637, 0, 0, 40000, 86, 0, 0 }, + { 638, 638, 0, 0, 3446, 1786, 0, 0 }, + { 346, 346, 0, 0, 540, 20, 0, 0 }, + { 639, 639, 0, 0, 7406, 2486, 0, 0 }, + { 404, 404, 0, 0, 1220, 466, 0, 0 }, + { 506, 506, 0, 0, 1000, 813, 0, 0 }, + { 639, 639, 60, 0, 2666, 913, 0, 0 }, + { 639, 639, 79, 0, 1366, 486, 0, 0 }, + { 640, 640, 65, 0, 2053, 646, 0, 0 }, + { 486, 486, 31, 0, 1206, 440, 0, 0 }, + { 486, 486, 36, 0, 1200, 433, 0, 0 }, + { 640, 640, 72, 0, 1713, 520, 0, 0 }, + { 136, 136, 79, 0, 1580, 560, 0, 0 }, + { 148, 148, 57, 0, 520, 206, 0, 0 }, + { 150, 150, 53, 0, 500, 193, 0, 0 }, + { 641, 641, 84, 0, 226, 66, 0, 0 }, + { 520, 520, 66, 0, 173, 20, 0, 0 }, + { 642, 642, 31, 0, 40000, 113, 0, 0 }, + { 642, 642, 29, 0, 40000, 113, 0, 0 }, + { 356, 356, 31, 0, 1366, 486, 0, 0 }, + { 356, 356, 19, 0, 1866, 633, 0, 0 }, + { 643, 643, 31, 0, 40000, 73, 0, 0 }, + { 643, 643, 29, 0, 40000, 73, 0, 0 }, + { 644, 644, 31, 0, 2286, 400, 0, 0 }, + { 644, 644, 35, 0, 2313, 420, 0, 0 }, + { 644, 644, 40, 0, 2353, 433, 0, 0 }, + { 644, 644, 47, 0, 1860, 346, 0, 0 }, + { 516, 516, 32, 0, 626, 240, 0, 0 }, + { 516, 516, 43, 0, 506, 200, 0, 0 }, + { 495, 495, 26, 0, 3180, 240, 0, 0 }, + { 495, 495, 44, 0, 2553, 206, 0, 0 }, + { 496, 496, 26, 0, 160, 73, 0, 0 }, + { 496, 496, 51, 0, 146, 66, 0, 0 }, + { 496, 496, 39, 0, 160, 73, 0, 0 }, + { 495, 495, 30, 0, 3180, 240, 0, 0 }, + { 645, 645, 44, 0, 1880, 653, 0, 0 }, + { 645, 645, 43, 0, 1886, 653, 0, 0 }, + { 646, 646, 0, 0, 2393, 833, 0, 0 }, + { 647, 647, 0, 0, 4693, 26, 0, 0 }, + { 648, 648, 0, 0, 2306, 773, 0, 0 }, + { 649, 649, 0, 0, 40000, 120, 0, 0 }, + { 650, 650, 0, 0, 40000, 66, 0, 0 }, + { 651, 651, 0, 0, 5866, 1206, 0, 0 }, + { 652, 652, 0, 0, 40000, 426, 0, 0 }, + { 653, 653, 0, 0, 1873, 633, 0, 0 }, + { 654, 654, 0, 0, 40000, 66, 0, 0 }, + { 655, 655, 0, 0, 40000, 73, 0, 0 }, + { 656, 656, 0, 0, 40000, 73, 0, 0 }, + { 657, 657, 0, 0, 40000, 0, 0, 0 }, + { 658, 658, 0, 0, 2040, 380, 0, 0 }, + { 659, 659, 0, 0, 40000, 73, 0, 0 }, + { 660, 660, 0, 0, 3720, 1260, 0, 0 }, + { 661, 661, 0, 0, 4080, 1046, 0, 0 }, + { 662, 662, 0, 0, 8693, 4666, 0, 0 }, + { 663, 663, 0, 0, 1926, 73, 0, 0 }, + { 664, 664, 0, 0, 8326, 646, 0, 0 }, + { 665, 665, 0, 0, 40000, 240, 0, 0 }, + { 666, 666, 0, 0, 40000, 226, 0, 0 }, + { 667, 667, 0, 0, 40000, 220, 0, 0 }, + { 668, 668, 0, 0, 40000, 0, 0, 0 }, + { 669, 669, 0, 0, 40000, 193, 0, 0 }, + { 670, 670, 0, 0, 880, 20, 0, 0 }, + { 671, 671, 0, 0, 4873, 120, 0, 0 }, + { 672, 672, 0, 0, 40000, 413, 0, 0 }, + { 673, 673, 0, 0, 700, 106, 0, 0 }, + { 674, 674, 0, 0, 700, 100, 0, 0 }, + { 675, 675, 0, 0, 40000, 126, 0, 0 }, + { 676, 676, 0, 0, 8113, 806, 0, 0 }, + { 677, 677, 0, 0, 8900, 80, 0, 0 }, + { 678, 678, 0, 0, 1893, 653, 0, 0 }, + { 679, 679, 0, 0, 3973, 206, 0, 0 }, + { 680, 680, 0, 0, 40000, 173, 0, 0 }, + { 681, 681, 0, 0, 40000, 73, 0, 0 }, + { 682, 682, 0, 0, 40000, 93, 0, 0 }, + { 683, 683, 0, 0, 1606, 640, 0, 0 }, + { 684, 684, 0, 0, 15486, 1580, 0, 0 }, + { 685, 685, 0, 0, 40000, 346, 0, 0 }, + { 686, 686, 0, 0, 40000, 786, 0, 0 }, + { 687, 687, 0, 0, 386, 240, 0, 0 }, + { 688, 688, 0, 0, 40000, 2066, 0, 0 }, + { 689, 689, 0, 0, 15453, 73, 0, 0 }, + { 690, 690, 0, 0, 1206, 240, 0, 0 }, + { 691, 691, 0, 0, 8866, 1366, 0, 0 }, + { 692, 692, 0, 0, 5913, 2253, 0, 0 }, + { 693, 693, 0, 0, 773, 106, 0, 0 }, + { 694, 694, 0, 0, 3793, 73, 0, 0 }, + { 695, 695, 0, 0, 40000, 73, 0, 0 }, + { 645, 645, 0, 0, 3633, 1180, 0, 0 }, + { 696, 696, 0, 0, 40000, 80, 0, 0 }, + { 697, 697, 0, 0, 40000, 0, 0, 0 }, + { 698, 698, 0, 0, 40000, 66, 0, 0 }, + { 699, 699, 0, 0, 40000, 66, 0, 0 }, + { 700, 700, 0, 0, 106, 53, 0, 0 }, + { 701, 701, 0, 0, 40000, 200, 0, 0 }, + { 702, 702, 0, 0, 3913, 73, 0, 0 }, + { 703, 703, 0, 0, 40000, 73, 0, 0 }, + { 704, 704, 0, 0, 40000, 73, 0, 0 }, + { 705, 705, 0, 0, 40000, 73, 0, 0 }, + { 706, 706, 0, 0, 40000, 66, 0, 0 }, + { 707, 707, 0, 0, 40000, 313, 0, 0 }, + { 708, 708, 0, 0, 40000, 100, 0, 0 }, + { 709, 709, 0, 0, 40000, 213, 0, 0 }, + { 710, 710, 0, 0, 40000, 53, 0, 0 }, + { 711, 711, 0, 0, 40000, 40, 0, 0 }, + { 712, 712, 0, 0, 40000, 73, 0, 0 }, + { 713, 713, 0, 0, 40000, 140, 0, 0 }, + { 714, 714, 0, 0, 40000, 606, 0, 0 }, + { 715, 715, 0, 0, 40000, 226, 0, 0 }, + { 716, 716, 0, 0, 3746, 1273, 0, 0 }, + { 717, 717, 0, 0, 40000, 80, 0, 0 }, + { 718, 718, 0, 0, 2360, 806, 0, 0 }, + { 719, 719, 0, 0, 1186, 420, 0, 0 }, + { 720, 720, 0, 0, 12533, 1953, 0, 0 }, + { 721, 721, 0, 0, 973, 1280, 0, 0 }, + { 722, 722, 0, 0, 40000, 426, 0, 0 }, + { 723, 723, 0, 0, 40000, 53, 0, 0 }, + { 724, 724, 0, 0, 40000, 66, 0, 0 }, + { 725, 725, 0, 0, 1246, 73, 0, 0 }, + { 726, 726, 0, 0, 3726, 1246, 0, 0 }, + { 727, 727, 0, 0, 2346, 813, 0, 0 }, + { 728, 728, 0, 0, 1206, 433, 0, 0 }, + { 507, 507, 0, 0, 306, 246, 0, 0 }, + { 512, 512, 0, 0, 526, 840, 0, 0 }, + { 729, 729, 0, 0, 14793, 4933, 0, 0 }, + { 730, 730, 0, 0, 14640, 4806, 0, 0 }, + { 731, 731, 0, 0, 5233, 633, 0, 0 }, + { 732, 732, 0, 0, 40000, 2513, 0, 0 }, + { 733, 733, 0, 0, 40000, 820, 0, 0 }, + { 734, 734, 0, 0, 40000, 0, 0, 0 }, + { 735, 735, 0, 0, 1726, 793, 0, 0 }, + { 736, 736, 0, 0, 513, 20, 0, 0 }, + { 737, 737, 0, 2, 6, 0, 0, 0 }, + { 738, 738, 38, 0, 1020, 413, 0, 0 }, + { 739, 739, 44, 0, 220, 33, 0, 0 }, + { 500, 500, 58, 0, 100, 26, 0, 0 }, + { 740, 740, 24, 0, 513, 206, 0, 0 }, + { 741, 741, 60, 0, 220, 26, 0, 0 }, + { 736, 736, 44, 0, 286, 20, 0, 0 }, + { 742, 742, 25, 0, 626, 246, 0, 0 }, + { 743, 743, 60, 0, 146, 86, 0, 0 }, + { 742, 742, 30, 0, 626, 240, 0, 0 }, + { 377, 377, 60, 0, 446, 626, 0, 0 }, + { 742, 742, 33, 0, 620, 226, 0, 0 }, + { 744, 744, 60, 0, 220, 113, 0, 0 }, + { 742, 742, 35, 0, 620, 233, 0, 0 }, + { 742, 742, 37, 0, 633, 246, 0, 0 }, + { 745, 745, 0, 0, 1880, 640, 0, 0 }, + { 742, 742, 40, 0, 640, 260, 0, 0 }, + { 746, 746,102, 0, 960, 300, 0, 0 }, + { 747, 747, 80, 0, 1106, 126, 0, 0 }, + { 377, 377, 0, 0, 500, 760, 0, 0 }, + { 748, 748, 56, 0, 100, 26, 0, 0 }, + { 749, 749, 0, 0, 973, 1300, 0, 0 }, + { 746, 746,100, 0, 960, 340, 0, 0 }, + { 750, 750, 40, 0, 626, 240, 0, 0 }, + { 750, 750, 35, 0, 626, 240, 0, 0 }, + { 751, 751, 29, 0, 206, 106, 0, 0 }, + { 750, 750, 29, 0, 633, 240, 0, 0 }, + { 750, 750, 22, 0, 640, 233, 0, 0 }, + { 500, 500, 0, 0, 106, 26, 0, 0 }, + { 752, 752, 0, 0, 206, 26, 0, 0 }, + { 753, 753, 84, 0, 166, 20, 0, 0 }, + { 754, 754, 84, 0, 1580, 553, 0, 0 }, + { 755, 755, 0, 0, 633, 233, 0, 0 }, + { 755, 755, 71, 0, 440, 180, 0, 0 }, + { 755, 755, 53, 0, 513, 200, 0, 0 }, + { 755, 755, 48, 0, 520, 206, 0, 0 }, + { 756, 756, 95, 0, 286, 20, 0, 0 }, + { 757, 757, 95, 0, 1880, 20, 0, 0 }, + { 758, 758, 0, 0, 14413, 333, 0, 0 }, + { 759, 759, 0, 0, 14453, 360, 0, 0 }, + { 760, 760, 0, 0, 14940, 353, 0, 0 }, + { 761, 761, 0, 0, 7286, 340, 0, 0 }, + { 762, 762, 0, 0, 14700, 60, 0, 0 }, + { 763, 763, 0, 0, 14506, 340, 0, 0 }, + { 764, 764, 0, 0, 14706, 200, 0, 0 }, + { 765, 765, 0, 0, 40000, 0, 0, 0 }, + { 766, 766, 0, 0, 2900, 426, 0, 0 }, + { 767, 767, 0, 0, 2986, 753, 0, 0 }, + { 768, 768, 0, 0, 1706, 680, 0, 0 }, + { 769, 769, 0, 0, 14646, 1253, 0, 0 }, + { 770, 770, 0, 0, 1713, 486, 0, 0 }, + { 771, 771, 0, 0, 966, 346, 0, 0 }, + { 772, 772, 0, 0, 3453, 766, 0, 0 }, + { 773, 773, 0, 0, 2866, 486, 0, 0 }, + { 774, 774, 0, 0, 40000, 73, 0, 0 }, + { 775, 775, 0, 0, 40000, 73, 0, 0 }, + { 776, 776, 0, 0, 40000, 166, 0, 0 }, + { 777, 777, 0, 0, 40000, 126, 0, 0 }, + { 778, 778, 0, 0, 40000, 113, 0, 0 }, + { 779, 779, 0, 0, 40000, 113, 0, 0 }, + { 780, 780, 0, 0, 40000, 93, 0, 0 }, + { 781, 781, 0, 0, 40000, 200, 0, 0 }, + { 782, 782, 0, 0, 7186, 93, 0, 0 }, + { 783, 783, 0, 0, 6406, 120, 0, 0 }, + { 784, 784, 0, 0, 40000, 0, 0, 0 }, + { 785, 785, 0, 0, 40000, 0, 0, 0 }, + { 786, 786, 0, 0, 1220, 73, 0, 0 }, + { 787, 787, 0, 0, 40000, 0, 0, 0 }, + { 788, 788, 0, 0, 17566, 66, 0, 0 }, + { 789, 789, 0, 0, 2333, 26, 0, 0 }, + { 790, 790, 0, 0, 4560, 153, 0, 0 }, + { 791, 791, 0, 0, 40000, 0, 0, 0 }, + { 792, 792, 0, 0, 40000, 0, 0, 0 }, + { 793, 793, 0, 0, 40000, 0, 0, 0 }, + { 794, 794, 0, 0, 2506, 126, 0, 0 }, + { 795, 795, 0, 0, 2513, 126, 0, 0 }, + { 796, 796, 0, 0, 40000, 0, 0, 0 }, + { 797, 797, 0, 0, 3386, 80, 0, 0 }, + { 798, 798, 0, 0, 40000, 100, 0, 0 }, + { 799, 799, 0, 0, 40000, 100, 0, 0 }, + { 800, 800, 0, 0, 40000, 120, 0, 0 }, + { 801, 801, 0, 0, 40000, 0, 0, 0 }, + { 802, 802, 0, 0, 40000, 200, 0, 0 }, + { 803, 803, 0, 0, 1080, 180, 0, 0 }, + { 804, 804, 0, 0, 3620, 1166, 0, 0 }, + { 805, 805, 0, 0, 1186, 393, 0, 0 }, + { 806, 806, 0, 0, 40000, 213, 0, 0 }, + { 807, 807, 0, 0, 40000, 426, 0, 0 }, + { 808, 808, 0, 0, 40000, 146, 0, 0 }, + { 809, 809, 0, 0, 40000, 146, 0, 0 }, + { 810, 810, 0, 0, 40000, 60, 0, 0 }, + { 811, 811, 0, 0, 40000, 113, 0, 0 }, + { 812, 812, 0, 0, 40000, 93, 0, 0 }, + { 813, 813, 0, 0, 1186, 153, 0, 0 }, + { 814, 814, 0, 0, 40000, 0, 0, 0 }, + { 815, 815, 0, 0, 40000, 80, 0, 0 }, + { 816, 816, 0, 0, 40000, 80, 0, 0 }, + { 817, 817, 0, 0, 40000, 46, 0, 0 }, + { 818, 818, 0, 0, 40000, 0, 0, 0 }, + { 819, 819, 0, 0, 40000, 66, 0, 0 }, + { 820, 820, 0, 0, 40000, 126, 0, 0 }, + { 821, 821, 0, 0, 40000, 213, 0, 0 }, + { 822, 822, 0, 0, 40000, 80, 0, 0 }, + { 823, 823, 0, 0, 40000, 73, 0, 0 }, + { 824, 824, 0, 0, 40000, 73, 0, 0 }, + { 825, 825, 0, 0, 40000, 100, 0, 0 }, + { 826, 826, 0, 0, 40000, 93, 0, 0 }, + { 827, 827, 0, 0, 40000, 73, 0, 0 }, + { 828, 828, 0, 0, 40000, 73, 0, 0 }, + { 829, 829, 0, 0, 40000, 80, 0, 0 }, + { 830, 830, 0, 0, 40000, 80, 0, 0 }, + { 831, 831, 0, 0, 40000, 80, 0, 0 }, + { 832, 832, 0, 0, 40000, 73, 0, 0 }, + { 833, 833, 0, 0, 40000, 80, 0, 0 }, + { 834, 834, 0, 0, 40000, 86, 0, 0 }, + { 835, 835, 0, 0, 40000, 100, 0, 0 }, + { 836, 836, 0, 0, 40000, 100, 0, 0 }, + { 837, 837, 0, 0, 40000, 140, 0, 0 }, + { 838, 838, 0, 0, 40000, 73, 0, 0 }, + { 839, 839, 0, 0, 40000, 0, 0, 0 }, + { 840, 840, 0, 0, 40000, 93, 0, 0 }, + { 841, 841, 0, 0, 40000, 0, 0, 0 }, + { 842, 842, 0, 0, 40000, 0, 0, 0 }, + { 843, 843, 0, 0, 40000, 73, 0, 0 }, + { 844, 844, 0, 0, 40000, 66, 0, 0 }, + { 845, 845, 0, 0, 40000, 0, 0, 0 }, + { 846, 846, 0, 0, 40000, 193, 0, 0 }, + { 847, 847, 0, 0, 40000, 340, 0, 0 }, + { 848, 848, 0, 0, 40000, 233, 0, 0 }, + { 849, 849, 0, 0, 40000, 80, 0, 0 }, + { 850, 850, 0, 0, 40000, 186, 0, 0 }, + { 851, 851, 0, 0, 9973, 426, 0, 0 }, + { 852, 852, 0, 0, 40000, 200, 0, 0 }, + { 853, 853, 0, 0, 40000, 400, 0, 0 }, + { 854, 854, 0, 0, 14633, 200, 0, 0 }, + { 855, 855, 0, 0, 40000, 333, 0, 0 }, + { 856, 856, 0, 0, 4620, 800, 0, 0 }, + { 857, 857, 0, 0, 8940, 386, 0, 0 }, + { 858, 858, 0, 0, 8966, 740, 0, 0 }, + { 859, 859, 0, 0, 40000, 273, 0, 0 }, + { 860, 860, 0, 0, 40000, 126, 0, 0 }, + { 861, 861, 0, 0, 40000, 400, 0, 0 }, + { 862, 862, 0, 0, 4480, 213, 0, 0 }, + { 863, 863, 0, 0, 633, 100, 0, 0 }, + { 864, 864, 0, 0, 3740, 353, 0, 0 }, + { 865, 865, 0, 0, 2333, 406, 0, 0 }, + { 866, 866, 0, 0, 1933, 566, 0, 0 }, + { 867, 867, 0, 0, 40000, 93, 0, 0 }, + { 868, 868, 0, 0, 40000, 106, 0, 0 }, + { 869, 869, 0, 0, 40000, 100, 0, 0 }, + { 870, 870, 0, 0, 3093, 240, 0, 0 }, + { 871, 871, 0, 0, 513, 93, 0, 0 }, + { 872, 872, 0, 0, 700, 180, 0, 0 }, + { 361, 361, 0, 0, 373, 40, 0, 0 }, + { 873, 873, 0, 0, 1046, 446, 0, 0 }, + { 874, 874, 0, 0, 1886, 520, 0, 0 }, + { 875, 875, 0, 0, 1226, 366, 0, 0 }, + { 876, 876, 0, 0, 4193, 73, 0, 0 }, + { 877, 877, 0, 0, 826, 120, 0, 0 }, + { 878, 878, 0, 0, 280, 146, 0, 0 }, + { 879, 879, 0, 0, 5266, 806, 0, 0 }, + { 880, 880, 0, 0, 386, 80, 0, 0 }, + { 881, 881, 0, 0, 40000, 100, 0, 0 }, + { 882, 882, 0, 0, 40000, 413, 0, 0 }, + { 883, 883, 0, 0, 40000, 0, 0, 0 }, + { 884, 884, 36, 0, 233, 80, 0, 0 }, + { 885, 885, 48, 0, 193, 93, 0, 0 }, + { 885, 885, 36, 0, 226, 100, 0, 0 }, + { 886, 886, 36, 0, 113, 53, 0, 0 }, + { 887, 887, 32, 0, 133, 40, 0, 0 }, + { 767, 767, 96, 0, 1760, 480, 0, 0 }, + { 888, 888, 30, 0, 246, 40, 0, 0 }, + { 889, 889, 35, 0, 420, 140, 0, 0 }, + { 890, 890, 60, 0, 240, 60, 0, 0 }, + { 884, 884, 59, 0, 146, 20, 0, 0 }, + { 890, 890, 44, 0, 240, 60, 0, 0 }, + { 891, 891, 41, 0, 713, 273, 0, 0 }, + { 892, 892, 47, 0, 173, 93, 0, 0 }, + { 891, 891, 44, 0, 513, 206, 0, 0 }, + { 891, 891, 48, 0, 506, 200, 0, 0 }, + { 893, 893, 62, 0, 1926, 93, 0, 0 }, + { 891, 891, 51, 0, 520, 200, 0, 0 }, + { 891, 891, 54, 0, 513, 206, 0, 0 }, + { 894, 894, 40, 0, 1280, 793, 0, 0 }, + { 891, 891, 57, 0, 380, 160, 0, 0 }, + { 895, 895, 97, 0, 233, 106, 0, 0 }, + { 896, 896, 50, 0, 220, 93, 0, 0 }, + { 376, 376, 60, 0, 1573, 713, 0, 0 }, + { 897, 897, 53, 0, 126, 73, 0, 0 }, + { 898, 898, 46, 0, 173, 133, 0, 0 }, + { 897, 897, 57, 0, 126, 33, 0, 0 }, + { 899, 899, 42, 0, 626, 233, 0, 0 }, + { 899, 899, 37, 0, 633, 240, 0, 0 }, + { 900, 900, 41, 0, 626, 240, 0, 0 }, + { 900, 900, 37, 0, 626, 240, 0, 0 }, + { 871, 871, 77, 0, 173, 40, 0, 0 }, + { 871, 871, 72, 0, 173, 40, 0, 0 }, + { 388, 388, 70, 0, 213, 86, 0, 0 }, + { 901, 901, 39, 0, 260, 26, 0, 0 }, + { 902, 902, 36, 0, 1093, 73, 0, 0 }, + { 903, 903, 46, 0, 120, 73, 0, 0 }, + { 904, 904, 48, 0, 766, 80, 0, 0 }, + { 905, 905, 85, 0, 126, 26, 0, 0 }, + { 361, 361, 66, 0, 180, 26, 0, 0 }, + { 906, 906, 41, 0, 193, 73, 0, 0 }, + { 907, 907, 41, 0, 333, 106, 0, 0 }, + { 908, 908, 81, 0, 160, 26, 0, 0 }, + { 400, 400, 10, 0, 1186, 413, 0, 0 }, + { 886, 886, 60, 0, 100, 40, 0, 0 }, + { 873, 873, 53, 0, 846, 360, 0, 0 }, + { 909, 909, 0, 0, 5593, 340, 0, 0 }, + { 910, 910, 0, 0, 14646, 346, 0, 0 }, + { 911, 911, 0, 0, 6826, 280, 0, 0 }, + { 912, 912, 0, 0, 7000, 306, 0, 0 }, + { 913, 913, 0, 0, 8793, 133, 0, 0 }, + { 914, 914, 0, 0, 14680, 346, 0, 0 }, + { 915, 915, 0, 0, 7246, 126, 0, 0 }, + { 916, 916, 0, 0, 40000, 0, 0, 0 }, + { 917, 917, 0, 0, 1866, 433, 0, 0 }, + { 362, 362, 0, 0, 1106, 340, 0, 0 }, + { 918, 918, 0, 0, 1053, 273, 0, 0 }, + { 919, 919, 0, 0, 14513, 1213, 0, 0 }, + { 920, 920, 0, 0, 1886, 646, 0, 0 }, + { 921, 921, 0, 0, 926, 313, 0, 0 }, + { 922, 922, 0, 0, 2340, 806, 0, 0 }, + { 923, 923, 0, 0, 2966, 553, 0, 0 }, + { 924, 924, 0, 0, 40000, 66, 0, 0 }, + { 925, 925, 0, 0, 40000, 73, 0, 0 }, + { 926, 926, 0, 0, 40000, 0, 0, 0 }, + { 927, 927, 0, 0, 40000, 126, 0, 0 }, + { 928, 928, 0, 0, 40000, 113, 0, 0 }, + { 929, 929, 0, 0, 40000, 113, 0, 0 }, + { 930, 930, 0, 0, 40000, 93, 0, 0 }, + { 931, 931, 0, 0, 40000, 113, 0, 0 }, + { 932, 932, 0, 0, 7200, 86, 0, 0 }, + { 933, 933, 0, 0, 5373, 106, 0, 0 }, + { 934, 934, 0, 0, 40000, 0, 0, 0 }, + { 935, 935, 0, 0, 40000, 0, 0, 0 }, + { 936, 936, 0, 0, 2380, 73, 0, 0 }, + { 937, 937, 0, 0, 40000, 0, 0, 0 }, + { 938, 938, 0, 0, 40000, 0, 0, 0 }, + { 939, 939, 0, 0, 6013, 53, 0, 0 }, + { 940, 940, 0, 0, 3713, 126, 0, 0 }, + { 941, 941, 0, 0, 17566, 26, 0, 0 }, + { 942, 942, 0, 0, 40000, 0, 0, 0 }, + { 943, 943, 0, 0, 40000, 0, 0, 0 }, + { 944, 944, 0, 0, 2506, 126, 0, 0 }, + { 945, 945, 0, 0, 3733, 73, 0, 0 }, + { 946, 946, 0, 0, 40000, 0, 0, 0 }, + { 947, 947, 0, 0, 3386, 80, 0, 0 }, + { 948, 948, 0, 0, 40000, 100, 0, 0 }, + { 949, 949, 0, 0, 40000, 100, 0, 0 }, + { 950, 950, 0, 0, 40000, 113, 0, 0 }, + { 951, 951, 0, 0, 40000, 0, 0, 0 }, + { 952, 952, 0, 0, 40000, 200, 0, 0 }, + { 953, 953, 0, 0, 1140, 213, 0, 0 }, + { 954, 954, 0, 0, 2140, 400, 0, 0 }, + { 955, 955, 0, 0, 813, 240, 0, 0 }, + { 956, 956, 0, 0, 40000, 100, 0, 0 }, + { 957, 957, 0, 0, 40000, 426, 0, 0 }, + { 958, 958, 0, 0, 40000, 0, 0, 0 }, + { 959, 959, 0, 0, 40000, 146, 0, 0 }, + { 960, 960, 0, 0, 40000, 120, 0, 0 }, + { 961, 961, 0, 0, 40000, 93, 0, 0 }, + { 962, 962, 0, 0, 1193, 153, 0, 0 }, + { 963, 963, 0, 0, 40000, 46, 0, 0 }, + { 964, 964, 0, 0, 40000, 80, 0, 0 }, + { 965, 965, 0, 0, 40000, 80, 0, 0 }, + { 966, 966, 0, 0, 40000, 20, 0, 0 }, + { 967, 967, 0, 0, 40000, 0, 0, 0 }, + { 968, 968, 0, 0, 40000, 93, 0, 0 }, + { 969, 969, 0, 0, 40000, 86, 0, 0 }, + { 970, 970, 0, 0, 40000, 213, 0, 0 }, + { 971, 971, 0, 0, 40000, 80, 0, 0 }, + { 972, 972, 0, 0, 40000, 73, 0, 0 }, + { 973, 973, 0, 0, 40000, 0, 0, 0 }, + { 974, 974, 0, 0, 40000, 93, 0, 0 }, + { 975, 975, 0, 0, 40000, 73, 0, 0 }, + { 976, 976, 0, 0, 40000, 73, 0, 0 }, + { 977, 977, 0, 0, 40000, 66, 0, 0 }, + { 978, 978, 0, 0, 40000, 66, 0, 0 }, + { 979, 979, 0, 0, 40000, 100, 0, 0 }, + { 980, 980, 0, 0, 40000, 73, 0, 0 }, + { 981, 981, 0, 0, 40000, 73, 0, 0 }, + { 982, 982, 0, 0, 40000, 80, 0, 0 }, + { 983, 983, 0, 0, 40000, 100, 0, 0 }, + { 984, 984, 0, 0, 40000, 100, 0, 0 }, + { 985, 985, 0, 0, 40000, 100, 0, 0 }, + { 986, 986, 0, 0, 40000, 80, 0, 0 }, + { 987, 987, 0, 0, 40000, 73, 0, 0 }, + { 988, 988, 0, 0, 40000, 0, 0, 0 }, + { 989, 989, 0, 0, 40000, 86, 0, 0 }, + { 990, 990, 0, 0, 40000, 0, 0, 0 }, + { 991, 991, 0, 0, 40000, 0, 0, 0 }, + { 992, 992, 0, 0, 40000, 80, 0, 0 }, + { 993, 993, 0, 0, 40000, 86, 0, 0 }, + { 994, 994, 0, 0, 40000, 0, 0, 0 }, + { 995, 995, 0, 0, 40000, 0, 0, 0 }, + { 996, 996, 0, 0, 40000, 333, 0, 0 }, + { 997, 997, 0, 0, 40000, 180, 0, 0 }, + { 998, 998, 0, 0, 40000, 80, 0, 0 }, + { 999, 999, 0, 0, 40000, 120, 0, 0 }, + {1000,1000, 0, 0, 10006, 460, 0, 0 }, + {1001,1001, 0, 0, 40000, 186, 0, 0 }, + {1002,1002, 0, 0, 40000, 400, 0, 0 }, + {1003,1003, 0, 0, 20333, 260, 0, 0 }, + {1004,1004, 0, 0, 40000, 373, 0, 0 }, + {1005,1005, 0, 0, 4520, 400, 0, 0 }, + {1006,1006, 0, 0, 8213, 306, 0, 0 }, + {1007,1007, 0, 0, 8646, 360, 0, 0 }, + {1008,1008, 0, 0, 40000, 160, 0, 0 }, + {1009,1009, 0, 0, 40000, 133, 0, 0 }, + {1010,1010, 0, 0, 40000, 400, 0, 0 }, + {1011,1011, 0, 0, 4473, 193, 0, 0 }, + {1012,1012, 0, 0, 1813, 120, 0, 0 }, + {1013,1013, 0, 0, 3726, 353, 0, 0 }, + {1014,1014, 0, 0, 4400, 373, 0, 0 }, + {1015,1015, 0, 0, 953, 166, 0, 0 }, + {1016,1016, 0, 0, 40000, 73, 0, 0 }, + {1017,1017, 0, 0, 40000, 100, 0, 0 }, + {1018,1018, 0, 0, 40000, 100, 0, 0 }, + {1019,1019, 0, 0, 3100, 240, 0, 0 }, + { 444, 444, 0, 0, 513, 93, 0, 0 }, + {1020,1020, 0, 0, 626, 180, 0, 0 }, + { 449, 449, 0, 0, 373, 80, 0, 0 }, + { 453, 453, 0, 0, 40000, 0, 0, 0 }, + {1021,1021, 0, 0, 1020, 340, 0, 0 }, + {1022,1022, 0, 0, 1200, 366, 0, 0 }, + {1023,1023, 0, 0, 4193, 73, 0, 0 }, + {1024,1024, 0, 0, 820, 120, 0, 0 }, + {1025,1025, 0, 0, 680, 213, 0, 0 }, + {1026,1026, 0, 0, 5260, 806, 0, 0 }, + {1027,1027, 0, 0, 9193, 86, 0, 0 }, + {1028,1028, 0, 0, 40000, 100, 0, 0 }, + {1029,1029, 0, 0, 40000, 426, 0, 0 }, + {1030,1030, 0, 0, 40000, 260, 0, 0 }, + {1031,1031, 0, 0, 3480, 66, 0, 0 }, + {1032,1032, 32, 0, 133, 46, 0, 0 }, + {1033,1033, 30, 0, 200, 40, 0, 0 }, + {1034,1034, 96, 0, 146, 73, 0, 0 }, + {1035,1035, 60, 0, 553, 186, 0, 0 }, + {1036,1036, 0, 0, 13193, 260, 0, 0 }, + {1037,1037, 0, 0, 40000, 100, 0, 0 }, + {1038,1038, 0, 0, 7980, 66, 0, 0 }, + {1039,1039, 0, 0, 40000, 0, 0, 0 }, + {1040,1040, 0, 0, 980, 340, 0, 0 }, + {1041,1041, 0, 0, 7413, 2480, 0, 0 }, + {1042,1042, 0, 0, 2906, 520, 0, 0 }, + {1043,1043, 0, 0, 40000, 73, 0, 0 }, + {1044,1044, 0, 0, 40000, 53, 0, 0 }, + {1045,1045, 0, 0, 40000, 113, 0, 0 }, + {1046,1046, 0, 0, 5380, 113, 0, 0 }, + {1047,1047, 0, 0, 40000, 0, 0, 0 }, + {1048,1048, 0, 0, 2366, 73, 0, 0 }, + {1049,1049, 0, 0, 40000, 0, 0, 0 }, + {1050,1050, 0, 0, 18293, 80, 0, 0 }, + {1051,1051, 0, 0, 18466, 146, 0, 0 }, + {1052,1052, 0, 0, 9220, 73, 0, 0 }, + {1053,1053, 0, 0, 40000, 240, 0, 0 }, + {1054,1054, 0, 0, 40000, 0, 0, 0 }, + {1055,1055, 0, 0, 1086, 126, 0, 0 }, + {1056,1056, 0, 0, 3766, 73, 0, 0 }, + {1057,1057, 0, 0, 1186, 226, 0, 0 }, + {1058,1058, 0, 0, 3373, 73, 0, 0 }, + {1059,1059, 0, 0, 40000, 246, 0, 0 }, + {1060,1060, 0, 0, 340, 220, 0, 0 }, + {1061,1061, 0, 0, 1186, 386, 0, 0 }, + {1062,1062, 0, 0, 40000, 253, 0, 0 }, + {1063,1063, 0, 0, 40000, 440, 0, 0 }, + {1064,1064, 0, 0, 40000, 46, 0, 0 }, + {1065,1065, 0, 0, 40000, 80, 0, 0 }, + {1066,1066, 0, 0, 40000, 126, 0, 0 }, + {1067,1067, 0, 0, 40000, 133, 0, 0 }, + {1068,1068, 0, 0, 40000, 93, 0, 0 }, + {1069,1069, 0, 0, 40000, 86, 0, 0 }, + {1070,1070, 0, 0, 40000, 93, 0, 0 }, + {1071,1071, 0, 0, 40000, 66, 0, 0 }, + {1072,1072, 0, 0, 40000, 93, 0, 0 }, + {1073,1073, 0, 0, 40000, 73, 0, 0 }, + {1074,1074, 0, 0, 40000, 173, 0, 0 }, + {1075,1075, 0, 0, 586, 193, 0, 0 }, + {1076,1076, 0, 0, 40000, 146, 0, 0 }, + {1077,1077, 0, 0, 18460, 73, 0, 0 }, + {1078,1078, 0, 0, 846, 93, 0, 0 }, + {1079,1079, 0, 0, 40000, 0, 0, 0 }, + {1080,1080, 0, 0, 40000, 86, 0, 0 }, + {1081,1081, 0, 0, 40000, 0, 0, 0 }, + {1082,1082, 0, 0, 40000, 353, 0, 0 }, + {1083,1083, 0, 0, 40000, 300, 0, 0 }, + {1084,1084, 0, 0, 40000, 320, 0, 0 }, + {1085,1085, 0, 0, 9920, 1553, 0, 0 }, + {1086,1086, 0, 0, 40000, 386, 0, 0 }, + {1087,1087, 0, 0, 40000, 0, 0, 0 }, + {1088,1088, 0, 0, 9980, 873, 0, 0 }, + {1089,1089, 0, 0, 40000, 386, 0, 0 }, + {1090,1090, 0, 0, 966, 126, 0, 0 }, + {1091,1091, 0, 0, 40000, 820, 0, 0 }, + {1092,1092, 0, 0, 8620, 366, 0, 0 }, + {1093,1093, 0, 0, 40000, 826, 0, 0 }, + {1094,1094, 0, 0, 40000, 433, 0, 0 }, + {1095,1095, 0, 0, 633, 73, 0, 0 }, + {1096,1096, 0, 0, 3693, 126, 0, 0 }, + {1097,1097, 0, 0, 40000, 0, 0, 0 }, + {1098,1098, 0, 0, 40000, 153, 0, 0 }, + {1099,1099, 0, 0, 40000, 0, 0, 0 }, + {1100,1100, 0, 0, 40000, 0, 0, 0 }, + {1101,1101, 0, 0, 40000, 306, 0, 0 }, + {1102,1102, 0, 0, 3666, 3093, 0, 0 }, + {1103,1103, 0, 0, 1873, 653, 0, 0 }, + {1104,1104, 0, 0, 40000, 0, 0, 0 }, + {1105,1105, 0, 0, 11293, 886, 0, 0 }, + {1106,1106, 0, 0, 40000, 546, 0, 0 }, + { 430, 430, 0, 0, 1146, 80, 0, 0 }, + {1107,1107, 35, 0, 580, 80, 0, 0 }, + {1090,1090, 77, 0, 280, 60, 0, 0 }, + {1090,1090, 72, 0, 280, 60, 0, 0 }, + {1108,1108, 0, 0, 10180, 600, 0, 0 }, + {1109,1109, 0, 0, 10053, 353, 0, 0 }, + {1110,1111, 0, 1, 9940, 480, 0, 0 }, + {1112,1113, 0, 1, 10620, 473, 0, 0.03125 }, + {1114,1114, 0, 0, 40000, 0, 0, 0 }, + {1115,1116, 0, 1, 9833, 220, 0, 0 }, + {1117,1117, 0, 0, 10286, 473, 0, 0 }, + {1118,1118, 0, 0, 7686, 93, 0, 0 }, + {1119,1119, 0, 0, 7220, 613, 0, 0 }, + {1120,1120, 0, 0, 11513, 1666, 0, 0 }, + {1121,1121, 0, 0, 5200, 1700, 0, 0 }, + {1122,1122, 0, 0, 10173, 626, 0, 0 }, + {1123,1123, 0, 0, 1206, 380, 0, 0 }, + {1124,1124, 0, 0, 1953, 866, 0, 0 }, + {1125,1125, 0, 0, 4686, 1586, 0, 0 }, + {1126,1126, 0, 0, 3786, 893, 0, 0 }, + {1127,1127, 0, 0, 40000, 126, 0, 0 }, + {1128,1128, 0, 0, 40000, 120, 0, 0 }, + {1129,1130, 0, 1, 40000, 146, 0, 0.15625 }, + {1131,1131, 0, 0, 40000, 433, 0, 0 }, + {1132,1132, 0, 0, 40000, 133, 0, 0 }, + {1133,1134, 0, 1, 40000, 126, 0, -0.046875 }, + {1135,1135, 0, 0, 40000, 113, 0, 0 }, + {1136,1137, 0, 1, 40000, 253, 0, 2.5e-05 }, + {1138,1138, 0, 0, 18440, 240, 0, 0 }, + {1139,1139, 0, 0, 5213, 886, 0, 0 }, + {1140,1140, 0, 0, 1446, 113, 0, 0 }, + {1141,1141, 0, 0, 5233, 106, 0, 0 }, + {1142,1142, 0, 0, 5286, 266, 0, 0 }, + {1143,1143, 0, 0, 40000, 66, 0, 0 }, + {1144,1144, 0, 0, 40000, 66, 0, 0 }, + {1145,1145, 0, 0, 10593, 106, 0, 0 }, + {1146,1146, 0, 0, 2733, 160, 0, 0 }, + {1147,1147, 0, 0, 10313, 93, 0, 0 }, + {1148,1148, 0, 0, 40000, 0, 0, 0 }, + {1149,1150, 0, 1, 40000, 0, 0, -0.03125 }, + {1151,1151, 0, 0, 40000, 53, 0, 0 }, + {1152,1152, 0, 0, 10560, 246, 0, 0 }, + {1153,1153, 0, 0, 2700, 153, 0, 0 }, + {1154,1154, 0, 1, 40000, 100, 0, -0.15625 }, + {1155,1155, 0, 0, 40000, 73, 0, 0 }, + {1156,1156, 0, 0, 40000, 220, 0, 0 }, + {1157,1157, 0, 0, 40000, 140, 0, 0 }, + {1158,1158, 0, 0, 40000, 380, 0, 0 }, + {1159,1160, 0, 1, 40000, 400, 0, 0.171875 }, + {1161,1161, 0, 0, 40000, 0, 0, 0 }, + {1162,1162, 0, 0, 40000, 0, 0, 0 }, + {1163,1163, 0, 0, 4733, 906, 0, 0 }, + {1164,1165, 0, 1, 40000, 393, 0, -0.125 }, + {1166,1167, 0, 1, 40000, 366, 0, 0.078125 }, + {1168,1168, 0, 1, 40000, 2453, 0, -0.078125 }, + {1169,1170, 0, 1, 40000, 546, 0, 0.0625 }, + {1171,1172, 0, 1, 40000, 786, 0, 0.15625 }, + {1173,1173, 0, 0, 40000, 0, 0, 0 }, + {1174,1174, 0, 0, 40000, 513, 0, 0 }, + {1175,1176, 0, 1, 2300, 533, 0, 0 }, + {1177,1177, 0, 0, 40000, 80, 0, 0 }, + {1178,1178, 0, 0, 40000, 60, 0, 0 }, + {1179,1179, 0, 0, 40000, 0, 0, 0 }, + {1180,1180, 0, 0, 10653, 86, 0, 0 }, + {1181,1182, 0, 1, 40000, 0, 0, 2.5e-05 }, + {1183,1184, 0, 1, 40000, 86, 0, 0.046875 }, + {1185,1186, 0, 1, 40000, 0, 0, 0.09375 }, + {1187,1188, 0, 1, 40000, 0, 0, 0.09375 }, + {1189,1189, 0, 0, 40000, 133, 0, 0 }, + {1190,1190, 0, 0, 40000, 140, 0, 0 }, + {1191,1191, 0, 0, 40000, 73, 0, 0 }, + {1192,1192, 0, 0, 40000, 60, 0, 0 }, + {1193,1193, 0, 0, 40000, 106, 0, 0 }, + {1194,1194, 0, 0, 40000, 93, 0, 0 }, + {1195,1195, 0, 0, 40000, 66, 0, 0 }, + {1196,1196, 0, 0, 40000, 93, 0, 0 }, + {1197,1197, 0, 0, 40000, 60, 0, 0 }, + {1198,1198, 0, 0, 40000, 66, 0, 0 }, + {1199,1199, 0, 0, 40000, 120, 0, 0 }, + {1200,1200, 0, 0, 40000, 100, 0, 0 }, + {1201,1201, 0, 0, 40000, 86, 0, 0 }, + {1202,1202, 0, 0, 40000, 0, 0, 0 }, + {1203,1203, 0, 0, 40000, 233, 0, 0 }, + {1204,1204, 0, 0, 40000, 100, 0, 0 }, + {1205,1206, 0, 1, 40000, 266, 0, 0.03125 }, + {1207,1208, 0, 1, 40000, 260, 0, -2.5e-05 }, + {1209,1209, 0, 0, 40000, 146, 0, 0 }, + {1210,1211, 0, 1, 40000, 60, 0, 0.03125 }, + {1212,1212, 0, 0, 40000, 53, 0, 0 }, + {1213,1214, 0, 1, 40000, 706, 0, -0.09375 }, + {1215,1216, 0, 1, 40000, 660, 0, -0.046875 }, + {1217,1217, 0, 0, 40000, 133, 0, 0 }, + {1218,1219, 0, 1, 40000, 426, 0, 0.03125 }, + {1220,1220, 0, 1, 40000, 0, 0, 0.03125 }, + {1221,1222, 0, 1, 40000, 260, 0, 0.171875 }, + {1223,1223, 0, 0, 40000, 0, 0, 0 }, + {1224,1224, 0, 0, 6100, 1580, 0, 0 }, + {1225,1150, 0, 1, 40000, 73, 0, -0.03125 }, + {1226,1226, 0, 0, 40000, 1580, 0, 0 }, + {1227,1227, 0, 0, 40000, 40, 0, 0 }, + {1228,1229, 0, 1, 40000, 113, 0, 0.125 }, + {1230,1230, 0, 0, 2666, 846, 0, 0 }, + {1231,1232, 0, 1, 40000, 0, 0, -0.03125 }, + {1233,1234, 0, 1, 9233, 2413, 0, -0.1875 }, + {1235,1235, 0, 0, 40000, 1020, 0, 0 }, + {1236,1236, 0, 0, 40000, 0, 0, 0 }, + {1237,1237, 0, 0, 9633, 3073, 0, 0 }, + {1238,1238, 0, 0, 40000, 0, 0, 0 }, + {1239,1239, 0, 0, 2446, 386, 0, 0 }, + {1240,1241, 0, 1, 3113, 1133, 0, 0 }, + {1242,1242, 0, 0, 18473, 813, 0, 0 }, + {1243,1243, 0, 0, 1206, 660, 0, 0 }, + {1244,1244, 0, 0, 40000, 153, 0, 0 }, + {1245,1245, 0, 0, 40000, 160, 0, 0 }, + {1246,1246, 0, 0, 40000, 133, 0, 0 }, + {1247,1247, 0, 0, 8660, 2386, 0, 0 }, + {1248,1248, 0, 0, 293, 106, 0, 0 }, + {1249,1249, 0, 0, 40000, 433, 0, 0 }, + {1250,1250, 0, 0, 426, 80, 0, 0 }, + {1251,1251, 0, 0, 973, 360, 0, 0 }, + {1252,1252, 0, 0, 573, 153, 0, 0 }, + {1253,1253, 0, 0, 3746, 126, 0, 0 }, + {1254,1254, 0, 0, 2313, 73, 0, 0 }, + {1255,1255, 0, 0, 1473, 106, 0, 0 }, + {1256,1256, 0, 0, 1500, 320, 0, 0 }, + {1257,1257, 0, 0, 5280, 1593, 0, 0 }, + {1258,1258, 0, 0, 40000, 60, 0, 0 }, + {1259,1259, 0, 0, 40000, 146, 0, 0 }, + {1260,1260, 29, 0, 40000, 300, 0, 0 }, + {1261,1261, 65, 0, 40000, 2040, 0, 0 }, + {1262,1262, 0, 0, 626, 240, 0, 0 }, + {1263,1263, 25, 0, 626, 226, 0, 0 }, + {1264,1264, 83, 0, 180, 80, 0, 0 }, + {1265,1265, 32, 0, 260, 140, 0, 0 }, + {1266,1266, 60, 0, 40000, 0, 0, 0 }, + {1267,1267, 36, 0, 286, 40, 0, 0 }, + {1268,1268, 27, 0, 573, 80, 0, 0 }, + {1269,1269, 31, 0, 693, 106, 0, 0 }, + {1270,1270, 21, 0, 500, 146, 0, 0 }, + {1270,1270, 26, 0, 493, 140, 0, 0 }, + {1270,1270, 28, 0, 500, 146, 0, 0 }, + {1271,1271, 60, 0, 2420, 1080, 0, 0 }, + {1270,1270, 32, 0, 413, 126, 0, 0 }, + {1272,1272, 60, 0, 806, 300, 0, 0 }, + {1273,1273, 96, 0, 1146, 493, 0, 0 }, + {1274,1274, 72, 0, 1246, 586, 0, 0 }, + {1275,1275, 79, 0, 286, 106, 0, 0 }, + {1276,1276, 69, 0, 1193, 1046, 0, 0 }, + {1277,1277, 71, 0, 340, 93, 0, 0 }, + {1278,1278, 22, 0, 1880, 653, 0, 0 }, + {1279,1279, 55, 0, 246, 120, 0, 0 }, + {1279,1279, 48, 0, 286, 133, 0, 0 }, + {1280,1280, 0, 0, 40, 93, 0, 0 }, + {1281,1281, 49, 2, 40, 93, 0, 0 }, + {1282,1282, 73, 0, 166, 33, 0, 0 }, + {1282,1282, 68, 0, 166, 33, 0, 0 }, + {1282,1282, 61, 0, 200, 40, 0, 0 }, + {1283,1283, 0, 0, 40, 93, 0, 0 }, + {1284,1284, 0, 0, 40000, 100, 0, 0 }, + {1285,1285, 0, 0, 40000, 60, 0, 0 }, + {1286,1286, 0, 0, 40000, 0, 0, 0 }, + {1287,1287, 0, 0, 10460, 153, 0, 0 }, + {1288,1289, 0, 1, 40000, 0, 0, 0 }, + {1290,1290, 0, 0, 40000, 0, 0, 0 }, + {1291,1292, 36, 1, 353, 153, 0, 0 }, + {1293,1293, 69, 0, 1206, 1060, 0, 0 }, + {1294,1294, 0, 0, 40000, 0, 0, 0 }, + {1295,1295, 0, 0, 40000, 73, 0, 0 }, + {1296,1296, 0, 0, 40000, 0, 0, 0 }, + {1297,1297, 22, 0, 1880, 653, 0, 0 }, + {1298,1298, 0, 0, 40000, 73, 0, 0 }, + {1299,1299, 0, 0, 3913, 420, 0, 0 }, + {1300,1300, 0, 0, 9233, 240, 0, 0 }, + {1301,1301, 0, 0, 4660, 1573, 0, 0 }, + {1302,1302, 0, 0, 1166, 400, 0, 0 }, + {1303,1303, 0, 0, 40000, 126, 0, 0 }, + {1304,1304, 0, 0, 40000, 93, 0, 0 }, + {1305,1305, 0, 0, 40000, 93, 0, 0 }, + {1306,1306, 0, 0, 40000, 553, 0, 0 }, + {1307,1307, 0, 0, 40000, 660, 0, 0 }, + {1308,1308, 0, 0, 40000, 73, 0, 0 }, + {1309,1309, 0, 0, 40000, 146, 0, 0 }, + {1310,1310, 0, 0, 40000, 146, 0, 0 }, + {1311,1311, 0, 0, 4026, 100, 0, 0 }, + {1312,1312, 0, 0, 18226, 100, 0, 0 }, + {1313,1313, 0, 0, 40000, 0, 0, 0 }, + {1314,1314, 0, 0, 40000, 73, 0, 0 }, + {1315,1315, 0, 0, 40000, 140, 0, 0 }, + {1316,1316, 0, 0, 40000, 393, 0, 0 }, + {1317,1317, 0, 0, 40000, 406, 0, 0 }, + {1318,1318, 0, 0, 40000, 373, 0, 0 }, + {1319,1319, 0, 0, 40000, 0, 0, 0 }, + {1320,1320, 0, 0, 40000, 360, 0, 0 }, + {1321,1321, 0, 0, 1060, 380, 0, 0 }, + {1322,1322, 0, 0, 40000, 66, 0, 0 }, + {1323,1323, 0, 0, 40000, 66, 0, 0 }, + {1324,1324, 0, 0, 40000, 86, 0, 0 }, + {1325,1325, 0, 0, 40000, 73, 0, 0 }, + { 260, 260, 0, 0, 40000, 80, 0, 0 }, + {1326,1326, 0, 0, 40000, 80, 0, 0 }, + {1327,1327, 0, 0, 40000, 73, 0, 0 }, + {1328,1328, 0, 0, 40000, 73, 0, 0 }, + {1329,1329, 0, 0, 40000, 153, 0, 0 }, + {1330,1330, 0, 0, 40000, 153, 0, 0 }, + {1331,1331, 0, 0, 40000, 146, 0, 0 }, + {1332,1332, 0, 0, 40000, 146, 0, 0 }, + {1333,1333, 0, 0, 40000, 73, 0, 0 }, + {1334,1334, 0, 0, 40000, 153, 0, 0 }, + {1335,1335, 0, 0, 40000, 233, 0, 0 }, + {1336,1336, 0, 0, 40000, 400, 0, 0 }, + {1337,1337, 0, 0, 40000, 1373, 0, 0 }, + {1338,1338, 0, 0, 40000, 193, 0, 0 }, + {1339,1339, 0, 0, 40000, 1273, 0, 0 }, + {1340,1340, 0, 0, 40000, 186, 0, 0 }, + {1341,1341, 0, 0, 40000, 86, 0, 0 }, + {1342,1342, 0, 0, 7440, 2473, 0, 0 }, + {1343,1343, 0, 0, 40000, 160, 0, 0 }, + {1344,1344, 0, 0, 8966, 406, 0, 0 }, + {1345,1345, 0, 0, 40000, 1353, 0, 0 }, + {1346,1346, 0, 0, 14180, 4406, 0, 0 }, + { 378, 378, 84, 0, 1333, 460, 0, 0 }, + {1347,1347, 24, 0, 1893, 633, 0, 0 }, + {1348,1348, 44, 0, 206, 86, 0, 0 }, + {1349,1349, 40, 0, 586, 140, 0, 0 }, + {1350,1350, 60, 0, 1026, 320, 0, 0 }, + {1351,1351, 0, 0, 6560, 33, 0, 0 }, + {1352,1352, 0, 0, 7373, 2453, 0, 0 }, + {1353,1353, 0, 0, 4660, 1573, 0, 0 }, + {1354,1354, 0, 0, 40000, 346, 0, 0 }, + {1355,1355, 0, 0, 7126, 86, 0, 0 }, + {1356,1356, 0, 0, 40000, 213, 0, 0 }, + {1357,1357, 0, 0, 1180, 340, 0, 0 }, + {1358,1358, 0, 0, 3893, 1466, 0, 0 }, + {1359,1359, 0, 0, 2053, 1173, 0, 0 }, + {1360,1360, 0, 0, 40000, 200, 0, 0 }, + {1361,1361, 0, 0, 40000, 353, 0, 0 }, + {1362,1362, 0, 0, 40000, 273, 0, 0 }, + {1363,1363, 0, 0, 40000, 433, 0, 0 }, + {1364,1364, 0, 0, 1940, 426, 0, 0 }, + {1365,1365, 0, 0, 40000, 80, 0, 0 }, + {1366,1366, 0, 0, 40000, 106, 0, 0 }, + {1367,1367, 0, 0, 40000, 60, 0, 0 }, + {1368,1368, 0, 0, 40000, 140, 0, 0 }, + {1369,1369, 0, 0, 40000, 93, 0, 0 }, + {1370,1370, 0, 0, 40000, 73, 0, 0 }, + {1371,1371, 0, 0, 40000, 73, 0, 0 }, + {1372,1372, 0, 0, 40000, 93, 0, 0 }, + {1373,1373, 0, 0, 40000, 73, 0, 0 }, + {1374,1374, 0, 0, 40000, 80, 0, 0 }, + {1375,1375, 0, 0, 40000, 746, 0, 0 }, + {1376,1376, 0, 0, 2360, 813, 0, 0 }, + {1377,1377, 0, 0, 340, 146, 0, 0 }, + {1378,1378, 35, 0, 713, 273, 0, 0 }, + {1379,1379, 49, 0, 173, 93, 0, 0 }, + {1377,1377, 48, 0, 286, 126, 0, 0 }, + {1380,1380, 58, 0, 173, 100, 0, 0 }, + {1377,1377, 60, 0, 286, 133, 0, 0 }, + {1381,1381, 47, 0, 973, 360, 0, 0 }, + {1382,1382, 60, 0, 146, 86, 0, 0 }, + {1381,1381, 49, 0, 966, 333, 0, 0 }, + {1383,1383, 72, 0, 506, 206, 0, 0 }, + {1381,1381, 51, 0, 953, 340, 0, 0 }, + {1384,1384, 84, 0, 1340, 480, 0, 0 }, + {1381,1381, 54, 0, 986, 360, 0, 0 }, + {1381,1381, 57, 0, 980, 346, 0, 0 }, + {1385,1385, 72, 0, 1573, 440, 0, 0 }, + {1381,1381, 60, 0, 953, 340, 0, 0 }, + {1386,1386, 36, 0, 2673, 900, 0, 0 }, + {1387,1387, 93, 0, 233, 106, 0, 0 }, + {1388,1388, 72, 0, 966, 353, 0, 0 }, + {1389,1389, 84, 0, 1366, 473, 0, 0 }, + {1390,1390, 36, 0, 1326, 446, 0, 0 }, + {1391,1391, 64, 0, 220, 86, 0, 0 }, + {1392,1392, 68, 0, 126, 220, 0, 0 }, + {1393,1393, 0, 0, 4513, 640, 0, 0 }, + {1394,1394, 0, 0, 40000, 353, 0, 0 }, + {1395,1395, 0, 0, 40000, 73, 0, 0 }, + {1396,1396, 0, 0, 2040, 380, 0, 0 }, + {1397,1397, 0, 0, 40000, 240, 0, 0 }, + {1398,1398, 0, 0, 3246, 753, 0, 0 }, + {1399,1399, 0, 0, 40000, 66, 0, 0 }, + {1400,1400, 0, 0, 40000, 0, 0, 0 }, + {1401,1401, 0, 0, 40000, 0, 0, 0 }, + {1402,1402, 0, 0, 7720, 1260, 0, 0 }, + {1403,1403, 0, 0, 213, 6420, 0, 0 }, + {1404,1404, 0, 0, 40000, 66, 0, 0 }, + {1405,1405, 0, 0, 40000, 73, 0, 0 }, + {1406,1406, 0, 0, 40000, 93, 0, 0 }, + {1407,1407, 0, 0, 1606, 640, 0, 0 }, + {1408,1408, 0, 0, 15486, 1580, 0, 0 }, + {1409,1409, 0, 0, 40000, 353, 0, 0 }, + {1410,1410, 0, 0, 40000, 2066, 0, 0 }, + {1411,1411, 0, 0, 40000, 0, 0, 0 }, + {1412,1412, 0, 0, 15453, 73, 0, 0 }, + {1413,1413, 0, 0, 3726, 1240, 0, 0 }, + {1414,1414, 0, 0, 40000, 86, 0, 0 }, + {1415,1415, 0, 0, 40000, 200, 0, 0 }, + {1416,1416, 0, 0, 40000, 53, 0, 0 }, + {1417,1417, 0, 0, 40000, 73, 0, 0 }, + {1418,1418, 0, 0, 40000, 66, 0, 0 }, + {1419,1419, 0, 0, 40000, 26, 0, 0 }, + {1420,1420, 0, 0, 40000, 53, 0, 0 }, + {1421,1421, 0, 0, 40000, 40, 0, 0 }, + {1422,1422, 0, 0, 40000, 126, 0, 0 }, + {1423,1423, 0, 0, 40000, 0, 0, 0 }, + {1424,1424, 0, 0, 13653, 4720, 0, 0 }, + {1425,1425, 0, 0, 12533, 1953, 0, 0 }, + {1426,1426, 0, 0, 973, 1280, 0, 0 }, + {1427,1427, 0, 0, 40000, 426, 0, 0 }, + {1428,1428, 0, 0, 40000, 53, 0, 0 }, + {1429,1429, 0, 0, 40000, 66, 0, 0 }, + {1430,1430, 0, 0, 526, 840, 0, 0 }, + {1431,1431, 0, 0, 286, 1293, 0, 0 }, + {1432,1432, 0, 0, 14726, 4920, 0, 0 }, + {1433,1433, 0, 0, 5233, 633, 0, 0 }, + {1434,1434, 0, 0, 13226, 2500, 0, 0 }, + { 740, 740, 0, 0, 513, 200, 0, 0 }, + {1435,1435, 0, 0, 40000, 5666, 0, 0 }, + { 739, 739, 48, 0, 213, 20, 0, 0 }, + { 500, 500, 55, 0, 100, 26, 0, 0 }, + { 740, 740, 60, 0, 226, 113, 0, 0 }, + { 500, 500, 41, 0, 106, 26, 0, 0 }, + {1436,1436, 84, 0, 160, 26, 0, 0 }, + {1437,1437, 84, 0, 386, 493, 0, 0 }, + { 500, 500, 48, 0, 100, 26, 0, 0 }, + {1438,1438, 15, 0, 340, 140, 0, 0 }, + { 752, 752, 49, 0, 173, 20, 0, 0 }, + {1438,1438, 16, 0, 346, 146, 0, 0 }, + {1438,1438, 12, 0, 340, 140, 0, 0 }, + { 740, 740, 55, 0, 220, 113, 0, 0 }, + { 752, 752, 18, 0, 206, 20, 0, 0 }, + { 752, 752, 15, 0, 200, 20, 0, 0 }, + { 752, 752, 17, 0, 206, 20, 0, 0 }, + {1439,1440, 0, 4, 40000, 0, 0, 0 }, + {1441,1442, 0, 4, 7320, 193, 0, 0 }, + {1443,1444, 0, 4, 11833, 320, 0, 0 }, + {1445,1446, 0, 4, 9920, 326, 0, 0 }, + {1447,1448, 0, 4, 10133, 26, 0, 0 }, + {1449,1450, 0, 4, 7373, 2486, 0, 0 }, + { 181,1451, 0, 4, 2313, 733, 0, 0 }, + {1452,1453, 0, 4, 9213, 240, 0, 0 }, + {1454,1455, 0, 4, 40000, 0, 0, 0 }, + {1456,1457, 0, 4, 660, 126, 0, 0 }, + {1458,1459, 0, 4, 40000, 66, 0, 0 }, + { 190,1460, 0, 4, 40000, 60, 0, 0 }, + { 192,1461, 0, 4, 40000, 73, 0, 0 }, + {1462,1463, 0, 4, 40000, 353, 0, 0 }, + {1464,1465, 0, 4, 40000, 353, 0, 0 }, + {1466,1467, 0, 4, 40000, 66, 0, 0 }, + {1468,1469, 0, 4, 40000, 46, 0, 0 }, + { 35,1470, 0, 4, 40000, 46, 0, 0 }, + { 36,1471, 0, 4, 320, 26, 0, 0 }, + {1472,1473, 0, 4, 320, 26, 0, 0 }, + {1474,1475, 0, 4, 7986, 93, 0, 0 }, + { 39,1476, 0, 4, 1046, 226, 0, 0 }, + {1477,1476, 0, 4, 1046, 226, 0, 0 }, + {1478,1479, 0, 4, 40000, 453, 0, 0 }, + { 50,1480, 0, 4, 40000, 400, 0, 0 }, + {1481,1482, 0, 4, 40000, 133, 0, 0 }, + {1483,1484, 0, 4, 40000, 0, 0, 0 }, + {1485,1486, 0, 4, 40000, 226, 0, 0 }, + { 55,1487, 0, 4, 40000, 100, 0, 0 }, + {1488,1489, 0, 4, 40000, 93, 0, 0 }, + {1490,1491, 0, 4, 40000, 73, 0, 0 }, + {1492,1493, 0, 4, 40000, 73, 0, 0 }, + {1494,1495, 0, 4, 40000, 73, 0, 0 }, + {1496,1497, 0, 4, 40000, 80, 0, 0 }, + {1496,1498, 0, 4, 40000, 73, 0, 0 }, + {1499,1500, 0, 4, 40000, 66, 0, 0 }, + {1501,1502, 0, 4, 40000, 146, 0, 0 }, + {1503,1504, 0, 4, 40000, 93, 0, 0 }, + {1505,1506, 0, 4, 40000, 73, 0, 0 }, + { 86,1507, 0, 4, 40000, 80, 0, 0 }, + {1508,1509, 0, 4, 40000, 0, 0, 0 }, + {1510,1511, 0, 4, 40000, 60, 0, 0 }, + {1512,1513, 0, 4, 40000, 0, 0, 0 }, + {1514,1515, 0, 4, 40000, 0, 0, 0 }, + {1516,1517, 0, 4, 40000, 766, 0, 0 }, + {1518,1519, 0, 4, 5286, 2966, 0, 0 }, + {1520,1521, 0, 4, 40000, 406, 0, 0 }, + {1522,1523, 0, 4, 9040, 360, 0, 0 }, + {1524,1525, 0, 4, 40000, 1200, 0, 0 }, + {1526,1527, 0, 4, 40000, 800, 0, 0 }, + {1528,1529, 0, 4, 40000, 960, 0, 0 }, + { 111,1530, 0, 4, 1193, 433, 0, 0 }, + {1531,1532, 0, 4, 220, 386, 0, 0 }, + { 115,1533, 0, 4, 2413, 1646, 0, 0 }, + {1534,1535, 0, 4, 1853, 640, 0, 0 }, + {1536,1537, 0, 4, 3006, 53, 0, 0 }, + {1538,1539, 0, 4, 1506, 720, 0, 0 }, + {1540, 339, 0, 6, 6, 0, 0, 0 }, + {1541, 339, 0, 6, 6, 0, 0, 0 }, + {1542,1543, 0, 4, 993, 93, 0, 0 }, + {1544,1545, 0, 4, 293, 86, 0, 0 }, + {1546,1547, 0, 4, 40000, 153, 0, 0 }, + { 364, 365, 44, 4, 120, 26, 0, 0 }, + { 129,1548, 48, 4, 173, 93, 0, 0 }, + { 367, 368, 58, 4, 173, 93, 0, 0 }, + { 129,1549, 60, 4, 173, 93, 0, 0 }, + {1550,1551, 48, 4, 520, 200, 0, 0 }, + { 132,1552, 43, 4, 173, 93, 0, 0 }, + {1550,1551, 49, 4, 520, 200, 0, 0 }, + {1553,1554, 43, 4, 160, 80, 0, 0 }, + {1550,1551, 51, 4, 513, 206, 0, 0 }, + { 134,1555, 43, 4, 1686, 613, 0, 0 }, + {1550,1551, 54, 4, 506, 200, 0, 0 }, + {1550,1551, 57, 4, 506, 200, 0, 0 }, + { 380, 381, 72, 4, 1573, 553, 0, 0 }, + {1550,1551, 60, 4, 513, 206, 0, 0 }, + {1556,1557, 70, 4, 766, 306, 0, 0 }, + { 374, 375, 60, 4, 973, 360, 0, 0 }, + {1558,1559, 36, 4, 1126, 420, 0, 0 }, + {1560,1561, 65, 4, 293, 133, 0, 0 }, + {1562,1563, 84, 4, 1353, 300, 0, 0 }, + {1564,1565, 59, 4, 380, 160, 0, 0 }, + {1566,1567, 84, 4, 1586, 566, 0, 0 }, + {1568,1569, 35, 4, 1320, 473, 0, 0 }, + {1570,1571, 44, 4, 406, 93, 0, 0 }, + {1572,1573, 67, 4, 246, 113, 0, 0 }, + {1574,1575, 66, 4, 286, 193, 0, 0 }, + { 145,1576, 59, 4, 140, 120, 0, 0 }, + {1577,1578, 51, 4, 326, 340, 0, 0 }, + {1579,1580, 45, 4, 233, 193, 0, 0 }, + {1581,1582, 71, 4, 433, 180, 0, 0 }, + { 149,1583, 60, 4, 280, 26, 0, 0 }, + {1584,1585, 58, 4, 166, 93, 0, 0 }, + {1586,1587, 53, 4, 173, 93, 0, 0 }, + { 397,1588, 64, 4, 213, 80, 0, 0 }, + {1589,1590, 71, 4, 106, 53, 0, 0 }, + {1591,1592, 61, 4, 973, 340, 0, 0 }, + {1593,1594, 61, 4, 986, 340, 0, 0 }, + { 391, 392, 48, 4, 160, 46, 0, 0 }, + { 391, 393, 48, 4, 380, 60, 0, 0 }, + {1595,1596, 69, 4, 120, 120, 0, 0 }, + { 159,1597, 68, 4, 120, 120, 0, 0 }, + { 159,1597, 63, 4, 140, 153, 0, 0 }, + {1598,1599, 74, 4, 893, 273, 0, 0 }, + {1600,1601, 60, 4, 1006, 306, 0, 0 }, + {1602,1603, 80, 4, 213, 106, 0, 0 }, + {1604,1605, 64, 4, 1346, 486, 0, 0 }, + {1606,1607, 69, 4, 120, 73, 0, 0 }, + { 398, 399, 55, 4, 1533, 193, 0, 0 }, + {1608,1609, 75, 4, 1560, 300, 0, 0 }, + {1610,1611, 68, 4, 120, 120, 0, 0 }, + {1612,1613, 48, 4, 333, 340, 0, 0 }, + {1614,1615, 53, 4, 593, 620, 0, 0 }, + {1616,1616, 0, 0, 40000, 1586, 0, 0 }, + {1617,1617, 0, 0, 40000, 1226, 0, 0 }, + {1618,1618, 0, 0, 4546, 766, 0, 0 }, + {1619,1619, 0, 0, 40000, 420, 0, 0 }, + {1620,1620, 0, 0, 40000, 1573, 0, 0 }, + {1621,1621, 0, 0, 3326, 806, 0, 0 }, + {1622,1622, 0, 0, 40000, 746, 0, 0 }, + {1623,1623, 0, 0, 40000, 900, 0, 0 }, + {1624,1624, 0, 0, 12166, 1573, 0, 0 }, + {1625,1625, 0, 0, 40000, 80, 0, 0 }, + {1626,1626, 0, 0, 40000, 80, 0, 0 }, + {1627,1627, 0, 0, 40000, 80, 0, 0 }, + {1628,1628, 0, 0, 40000, 2713, 0, 0 }, + {1629,1629, 0, 0, 40000, 86, 0, 0 }, + {1630,1630, 0, 0, 40000, 80, 0, 0 }, + {1631,1631, 0, 0, 40000, 80, 0, 0 }, + {1632,1632, 0, 0, 40000, 813, 0, 0 }, + {1633,1633, 0, 0, 40000, 80, 0, 0 }, + {1634,1634, 0, 0, 40000, 80, 0, 0 }, + {1635,1635, 0, 0, 40000, 80, 0, 0 }, + {1636,1636, 0, 0, 40000, 193, 0, 0 }, + {1637,1637, 0, 0, 2920, 733, 0, 0 }, + {1638,1638, 0, 0, 40000, 373, 0, 0 }, + {1639,1639, 0, 0, 2286, 226, 0, 0 }, + {1640,1640, 0, 0, 40000, 226, 0, 0 }, + {1641,1641, 0, 0, 40000, 226, 0, 0 }, + {1642,1642, 0, 0, 40000, 433, 0, 0 }, + {1643,1643, 0, 0, 40000, 813, 0, 0 }, + {1644,1644, 0, 0, 40000, 80, 0, 0 }, + {1645,1645, 0, 0, 40000, 80, 0, 0 }, + {1646,1646, 0, 0, 40000, 80, 0, 0 }, + {1647,1647, 0, 0, 40000, 80, 0, 0 }, + {1648,1648, 0, 0, 40000, 80, 0, 0 }, + {1649,1649, 0, 0, 40000, 80, 0, 0 }, + {1650,1650, 0, 0, 40000, 146, 0, 0 }, + {1651,1651, 0, 0, 40000, 1280, 0, 0 }, + {1652,1652, 0, 0, 40000, 513, 0, 0 }, + {1653,1653, 0, 0, 40000, 313, 0, 0 }, + {1654,1654, 0, 0, 40000, 773, 0, 0 }, + {1655,1655, 0, 0, 7400, 2480, 0, 0 }, + {1656,1656, 0, 0, 3760, 1253, 0, 0 }, + {1657,1657, 0, 0, 40000, 380, 0, 0 }, + {1658,1658, 0, 0, 40000, 333, 0, 0 }, + {1659,1659, 0, 0, 40000, 2926, 0, 0 }, + {1660,1660, 0, 0, 40000, 5666, 0, 0 }, + {1661,1661, 0, 0, 40000, 1613, 0, 0 }, + {1662,1662, 0, 0, 3746, 1273, 0, 0 }, + {1663,1663, 0, 0, 13653, 4720, 0, 0 }, + {1664,1664, 0, 0, 4640, 1553, 0, 0 }, + {1665,1665, 0, 0, 40000, 680, 0, 0 }, + {1666,1666, 0, 0, 6393, 426, 0, 0 }, + {1667,1667, 0, 0, 40000, 713, 0, 0 }, + {1668,1668, 12, 0, 166, 20, 0, 0 }, + {1669,1669, 48, 0, 460, 193, 0, 0 }, + { 736, 736, 52, 0, 286, 20, 0, 0 }, + {1670,1670, 48, 0, 506, 200, 0, 0 }, + {1670,1670, 36, 0, 713, 260, 0, 0 }, + { 377, 377, 84, 0, 386, 493, 0, 0 }, + { 730, 730, 95, 0, 1886, 653, 0, 0 }, + {1669,1669, 84, 0, 386, 166, 0, 0 }, + { 755, 755, 20, 0, 633, 240, 0, 0 }, + { 755, 755, 22, 0, 626, 240, 0, 0 }, + { 755, 755, 24, 0, 633, 246, 0, 0 }, + {1671,1671, 0, 0, 2233, 220, 0, 0 }, + {1672,1672, 0, 0, 2233, 240, 0, 0 }, + {1673,1673, 0, 0, 2233, 206, 0, 0 }, + {1674,1674, 0, 0, 2126, 173, 0, 0 }, + {1675,1675, 0, 0, 7473, 73, 0, 0 }, + {1676,1676, 0, 0, 40000, 0, 0, 0 }, + {1677,1677, 0, 0, 3493, 193, 0, 0 }, + {1678,1678, 0, 0, 1746, 73, 0, 0 }, + {1679,1679, 0, 0, 1013, 400, 0, 0 }, + {1680,1680, 0, 0, 3473, 1560, 0, 0 }, + {1681,1681, 0, 0, 1073, 40, 0, 0 }, + {1682,1682, 0, 0, 40000, 380, 0, 0 }, + {1683,1683, 0, 0, 1166, 400, 0, 0 }, + {1684,1684, 0, 0, 606, 146, 0, 0 }, + {1685,1685, 0, 0, 4553, 1486, 0, 0 }, + {1686,1686, 0, 0, 1126, 80, 0, 0 }, + {1687,1687, 0, 0, 40000, 73, 0, 0 }, + {1688,1688, 0, 0, 40000, 60, 0, 0 }, + {1689,1689, 0, 0, 40000, 66, 0, 0 }, + {1690,1690, 0, 0, 40000, 73, 0, 0 }, + {1691,1691, 0, 0, 40000, 73, 0, 0 }, + {1692,1692, 0, 0, 40000, 73, 0, 0 }, + {1693,1693, 0, 0, 40000, 73, 0, 0 }, + {1694,1694, 0, 0, 6380, 53, 0, 0 }, + {1695,1695, 0, 0, 6380, 60, 0, 0 }, + {1696,1696, 0, 0, 40000, 53, 0, 0 }, + {1697,1697, 0, 0, 40000, 0, 0, 0 }, + {1698,1698, 0, 0, 1880, 80, 0, 0 }, + {1699,1699, 0, 0, 40000, 60, 0, 0 }, + {1700,1700, 0, 0, 40000, 60, 0, 0 }, + {1701,1701, 0, 0, 1460, 80, 0, 0 }, + {1702,1702, 0, 0, 40000, 73, 0, 0 }, + {1703,1703, 0, 0, 40000, 0, 0, 0 }, + {1704,1704, 0, 0, 40000, 146, 0, 0 }, + {1705,1705, 0, 0, 40000, 66, 0, 0 }, + {1706,1706, 0, 0, 40000, 73, 0, 0 }, + {1707,1707, 0, 0, 40000, 160, 0, 0 }, + {1708,1708, 0, 0, 40000, 73, 0, 0 }, + {1709,1709, 0, 0, 40000, 193, 0, 0 }, + {1710,1710, 0, 0, 3740, 1260, 0, 0 }, + {1711,1711, 0, 0, 40000, 180, 0, 0 }, + {1712,1712, 0, 0, 40000, 173, 0, 0 }, + {1713,1713, 0, 0, 40000, 113, 0, 0 }, + {1714,1714, 0, 0, 40000, 86, 0, 0 }, + {1715,1715, 0, 0, 1853, 633, 0, 0 }, + {1716,1716, 0, 0, 40000, 0, 0, 0 }, + {1717,1717, 0, 0, 1066, 306, 0, 0 }, + {1718,1718, 0, 0, 40000, 86, 0, 0 }, + {1719,1719, 0, 0, 40000, 586, 0, 0 }, + {1720,1720, 0, 0, 40000, 86, 0, 0 }, + {1721,1721, 0, 0, 40000, 93, 0, 0 }, + {1722,1722, 0, 0, 40000, 373, 0, 0 }, + {1723,1723, 0, 0, 40000, 113, 0, 0 }, + {1724,1724, 0, 0, 40000, 353, 0, 0 }, + {1725,1725, 0, 0, 420, 73, 0, 0 }, + {1726,1726, 0, 0, 40000, 66, 0, 0 }, + {1727,1727, 0, 0, 40000, 53, 0, 0 }, + {1728,1728, 0, 0, 40000, 66, 0, 0 }, + {1729,1729, 0, 0, 40000, 100, 0, 0 }, + {1730,1730, 0, 0, 40000, 93, 0, 0 }, + {1731,1731, 0, 0, 40000, 0, 0, 0 }, + {1732,1732, 0, 0, 40000, 73, 0, 0 }, + {1733,1733, 0, 0, 40000, 80, 0, 0 }, + {1734,1734, 0, 0, 40000, 80, 0, 0 }, + {1735,1735, 0, 0, 40000, 80, 0, 0 }, + {1736,1736, 0, 0, 40000, 80, 0, 0 }, + {1737,1737, 0, 0, 40000, 80, 0, 0 }, + {1738,1738, 0, 0, 40000, 73, 0, 0 }, + {1739,1739, 0, 0, 40000, 73, 0, 0 }, + {1740,1740, 0, 0, 40000, 106, 0, 0 }, + {1741,1741, 0, 0, 40000, 73, 0, 0 }, + {1742,1742, 0, 0, 40000, 73, 0, 0 }, + {1743,1743, 0, 0, 40000, 80, 0, 0 }, + {1744,1744, 0, 0, 40000, 0, 0, 0 }, + {1745,1745, 0, 0, 40000, 80, 0, 0 }, + {1746,1746, 0, 0, 40000, 66, 0, 0 }, + {1747,1747, 0, 0, 40000, 73, 0, 0 }, + {1748,1748, 0, 0, 40000, 0, 0, 0 }, + {1749,1749, 0, 0, 40000, 80, 0, 0 }, + {1750,1750, 0, 0, 40000, 66, 0, 0 }, + {1751,1751, 0, 0, 40000, 73, 0, 0 }, + {1752,1752, 0, 0, 40000, 80, 0, 0 }, + {1753,1753, 0, 0, 40000, 33, 0, 0 }, + {1754,1754, 0, 0, 40000, 0, 0, 0 }, + {1755,1755, 0, 0, 40000, 266, 0, 0 }, + {1756,1756, 0, 0, 40000, 160, 0, 0 }, + {1757,1757, 0, 0, 40000, 93, 0, 0 }, + {1758,1758, 0, 0, 40000, 660, 0, 0 }, + {1759,1759, 0, 0, 40000, 1453, 0, 0 }, + {1760,1760, 0, 0, 40000, 660, 0, 0 }, + {1761,1761, 0, 0, 40000, 120, 0, 0 }, + {1762,1762, 0, 0, 40000, 140, 0, 0 }, + {1763,1763, 0, 0, 9820, 393, 0, 0 }, + {1764,1764, 0, 0, 40000, 73, 0, 0 }, + {1765,1765, 0, 0, 3620, 1166, 0, 0 }, + {1766,1766, 0, 0, 40000, 0, 0, 0 }, + {1767,1767, 0, 0, 40000, 0, 0, 0 }, + {1768,1768, 0, 0, 40000, 813, 0, 0 }, + {1769,1769, 0, 0, 40000, 0, 0, 0 }, + {1770,1770, 0, 0, 40000, 2386, 0, 0 }, + {1771,1771, 0, 0, 4380, 400, 0, 0 }, + {1772,1772, 0, 0, 853, 220, 0, 0 }, + {1773,1773, 0, 0, 3700, 93, 0, 0 }, + {1774,1774, 0, 0, 1580, 300, 0, 0 }, + {1775,1775, 0, 0, 453, 140, 0, 0 }, + {1776,1776, 0, 0, 40000, 66, 0, 0 }, + {1777,1777, 0, 0, 40000, 73, 0, 0 }, + {1778,1778, 0, 0, 40000, 206, 0, 0 }, + {1779,1779, 0, 0, 4646, 1560, 0, 0 }, + {1780,1780, 0, 0, 353, 146, 0, 0 }, + {1781,1781, 0, 0, 1300, 400, 0, 0 }, + {1782,1782, 0, 0, 4593, 1546, 0, 0 }, + {1783,1783, 0, 0, 613, 226, 0, 0 }, + {1784,1784, 0, 0, 626, 233, 0, 0 }, + {1785,1785, 0, 0, 3020, 66, 0, 0 }, + {1786,1786, 0, 0, 1093, 186, 0, 0 }, + {1787,1787, 0, 0, 6053, 1240, 0, 0 }, + {1788,1788, 0, 0, 633, 126, 0, 0 }, + {1789,1789, 0, 0, 40000, 66, 0, 0 }, + {1790,1790, 0, 0, 40000, 73, 0, 0 }, + {1791,1791, 0, 0, 40000, 1253, 0, 0 }, + {1792,1792, 0, 0, 626, 246, 0, 0 }, + {1793,1793, 48, 0, 293, 120, 0, 0 }, + {1794,1794, 48, 0, 100, 40, 0, 0 }, + {1795,1795, 60, 0, 240, 133, 0, 0 }, + {1796,1796, 60, 0, 160, 66, 0, 0 }, + {1797,1797, 70, 0, 140, 33, 0, 0 }, + {1798,1798, 51, 0, 526, 206, 0, 0 }, + {1799,1799, 60, 0, 173, 93, 0, 0 }, + {1798,1798, 54, 0, 520, 200, 0, 0 }, + {1800,1800, 60, 0, 153, 80, 0, 0 }, + {1798,1798, 56, 0, 520, 206, 0, 0 }, + {1801,1801, 60, 0, 673, 206, 0, 0 }, + {1798,1798, 61, 0, 506, 200, 0, 0 }, + {1798,1798, 63, 0, 513, 206, 0, 0 }, + {1802,1802, 48, 0, 673, 200, 0, 0 }, + {1798,1798, 68, 0, 440, 180, 0, 0 }, + {1803,1803, 60, 0, 1873, 653, 0, 0 }, + {1804,1804, 60, 0, 673, 200, 0, 0 }, + {1805,1805, 66, 0, 306, 120, 0, 0 }, + {1806,1806, 60, 0, 673, 200, 0, 0 }, + { 379, 379, 59, 0, 173, 93, 0, 0 }, + {1802,1802, 64, 0, 673, 206, 0, 0 }, + {1807,1807, 48, 0, 1006, 20, 0, 0 }, + {1808,1808, 56, 0, 120, 40, 0, 0 }, + {1809,1809, 53, 0, 286, 133, 0, 0 }, + {1810,1810, 65, 0, 106, 46, 0, 0 }, + {1811,1811, 49, 0, 293, 133, 0, 0 }, + {1811,1811, 43, 0, 293, 133, 0, 0 }, + { 386, 386, 65, 0, 1013, 673, 0, 0 }, + { 386, 386, 60, 0, 1000, 660, 0, 0 }, + {1812,1812, 70, 0, 260, 113, 0, 0 }, + {1812,1812, 65, 0, 306, 120, 0, 0 }, + {1813,1813, 60, 0, 246, 106, 0, 0 }, + {1814,1814, 60, 0, 193, 120, 0, 0 }, + {1815,1815, 56, 0, 206, 13, 0, 0 }, + {1816,1816, 53, 0, 433, 73, 0, 0 }, + {1817,1817, 60, 0, 220, 113, 0, 0 }, + {1818,1818, 48, 0, 300, 66, 0, 0 }, + {1819,1819, 69, 0, 126, 0, 0, 0 }, + { 328, 328, 67, 0, 140, 93, 0, 0 }, + { 328, 328, 62, 0, 153, 100, 0, 0 }, + {1820,1820, 65, 0, 433, 100, 0, 0 }, + {1821,1821, 60, 0, 426, 100, 0, 0 }, + {1822,1822, 63, 0, 113, 46, 0, 0 }, + {1823,1823, 63, 0, 1866, 653, 0, 0 }, + {1824,1824, 67, 0, 273, 60, 0, 0 }, + {1825,1825, 60, 0, 973, 360, 0, 0 }, + {1825,1825, 72, 0, 806, 273, 0, 0 }, + { 401, 401, 62, 0, 46, 33, 0, 0 }, + {1826,1826, 48, 0, 126, 66, 0, 0 }, + {1827,1827, 53, 0, 980, 353, 0, 0 }, + {1828,1828, 60, 0, 293, 133, 0, 0 }, + {1829,1829, 60, 0, 160, 20, 0, 0 }, + {1830,1830, 60, 0, 126, 86, 0, 0 }, + {1831,1831, 60, 0, 173, 93, 0, 0 }, + {1832,1832, 0, 0, 40000, 106, 0, 0 }, + {1833,1833, 0, 0, 3780, 73, 0, 0 }, + {1834,1834, 0, 0, 3820, 1666, 0, 0 }, + {1835,1835, 0, 0, 40000, 73, 0, 0 }, + {1836,1836, 0, 0, 40000, 333, 0, 0 }, + {1837,1837, 0, 0, 40000, 220, 0, 0 }, + {1838,1838, 0, 0, 40000, 0, 0, 0 }, + {1839,1839, 0, 0, 40000, 53, 0, 0 }, + {1840,1840, 0, 0, 40000, 60, 0, 0 }, + {1841,1841, 0, 0, 5913, 2306, 0, 0 }, + {1842,1842, 0, 0, 7713, 2466, 0, 0 }, + { 525, 525, 0, 0, 4660, 660, 0, 0 }, + {1843,1843, 0, 0, 40000, 313, 0, 0 }, + {1844,1844, 0, 0, 40000, 0, 0, 0 }, + {1845,1845, 0, 0, 40000, 0, 0, 0 }, + {1846,1846, 0, 0, 1246, 453, 0, 0 }, + {1847,1847, 0, 0, 9600, 1580, 0, 0 }, + {1848,1848, 0, 0, 40000, 106, 0, 0 }, + {1849,1849, 0, 0, 2040, 400, 0, 0 }, + {1850,1850, 0, 0, 40000, 73, 0, 0 }, + {1851,1851, 0, 0, 4220, 620, 0, 0 }, + {1852,1852, 0, 0, 40000, 0, 0, 0 }, + {1853,1853, 0, 0, 40000, 433, 0, 0 }, + {1854,1854, 0, 0, 40000, 66, 0, 0 }, + {1855,1855, 0, 0, 40000, 46, 0, 0 }, + {1856,1856, 0, 0, 40000, 240, 0, 0 }, + {1857,1857, 0, 0, 40000, 313, 0, 0 }, + {1858,1858, 0, 0, 40000, 26, 0, 0 }, + {1859,1859, 0, 0, 40000, 0, 0, 0 }, + {1860,1860, 0, 0, 40000, 73, 0, 0 }, + {1861,1861, 0, 0, 6940, 66, 0, 0 }, + {1862,1862, 0, 0, 40000, 0, 0, 0 }, + {1863,1863, 0, 0, 40000, 60, 0, 0 }, + {1864,1864, 0, 0, 8140, 1440, 0, 0 }, + {1865,1865, 0, 0, 40000, 0, 0, 0 }, + {1866,1866, 0, 0, 40000, 613, 0, 0 }, + {1867,1867, 0, 0, 40000, 0, 0, 0 }, + {1868,1868, 0, 0, 633, 233, 0, 0 }, + {1869,1869, 0, 0, 40000, 226, 0, 0 }, + {1870,1870, 0, 0, 2280, 746, 0, 0 }, + {1871,1871, 0, 0, 1940, 633, 0, 0 }, + {1872,1872, 0, 0, 4220, 620, 0, 0 }, + {1873,1873, 0, 0, 40000, 133, 0, 0 }, + {1874,1874, 41, 0, 380, 153, 0, 0 }, + {1875,1875, 70, 0, 106, 26, 0, 0 }, + {1876,1876, 60, 0, 380, 206, 0, 0 }, + {1877,1877, 80, 0, 100, 26, 0, 0 }, + {1878,1878, 84, 0, 120, 60, 0, 0 }, + {1879,1879, 72, 0, 500, 433, 0, 0 }, + {1880,1880, 84, 0, 860, 553, 0, 0 }, + { 128, 128, 70, 0, 106, 26, 0, 0 }, + { 132, 132, 60, 0, 146, 86, 0, 0 }, + {1881,1882, 0, 4, 40000, 260, 0, 0 }, + {1883,1883, 0, 0, 40000, 0, 0, 0 }, + {1884,1885, 0, 4, 40000, 73, 0, 0 }, + {1886,1887, 0, 4, 40000, 86, 0, 0 }, + {1888,1889, 0, 4, 40000, 73, 0, 0 }, + {1890,1890, 0, 0, 40000, 300, 0, 0 }, + {1891,1891, 0, 0, 40000, 693, 0, 0 }, + {1892,1892, 0, 0, 40000, 586, 0, 0 }, + {1893,1893, 0, 0, 40000, 286, 0, 0 }, + {1894,1894, 0, 0, 1620, 773, 0, 0 }, + {1895,1895, 0, 0, 40000, 0, 0, 0 }, + {1896,1896, 0, 0, 40000, 193, 0, 0 }, + {1897,1897, 0, 0, 1873, 820, 0, 0 }, + {1898,1898, 0, 0, 4520, 753, 0, 0 }, + {1899,1899, 0, 0, 40000, 0, 0, 0 }, + {1900,1900, 0, 0, 40000, 220, 0, 0 }, + {1901,1901, 0, 0, 40000, 133, 0, 0 }, + {1902,1902, 0, 0, 40000, 73, 0, 0 }, + {1903,1903, 0, 0, 40000, 0, 0, 0 }, + {1904,1904, 0, 0, 7326, 2420, 0, 0 }, + {1905,1905, 0, 0, 1186, 446, 0, 0 }, + {1906,1906, 0, 0, 40000, 553, 0, 0 }, + {1907,1907, 0, 0, 40000, 293, 0, 0 }, + {1908,1908, 0, 0, 40000, 586, 0, 0 }, + {1909,1909, 0, 0, 2326, 793, 0, 0 }, + { 501, 501, 0, 0, 480, 226, 0, 0 }, + {1910,1910, 0, 0, 40000, 93, 0, 0 }, + {1911,1911, 0, 0, 620, 226, 0, 0 }, + {1912,1912, 0, 0, 2373, 800, 0, 0 }, + {1913,1913, 0, 0, 40000, 4986, 0, 0 }, + {1914,1914, 0, 0, 626, 240, 0, 0 }, + { 511, 511, 0, 0, 2326, 800, 0, 0 }, + {1915,1915, 0, 0, 340, 146, 0, 0 }, + {1910,1910, 60, 0, 40000, 93, 0, 0 }, + { 511, 511, 72, 0, 1566, 546, 0, 0 }, + {1915,1915, 84, 0, 246, 120, 0, 0 }, + {1916,1916, 0, 0, 40000, 0, 0, 0 }, + {1917,1917, 0, 0, 2713, 666, 0, 0 }, + {1918,1918, 0, 0, 40000, 0, 0, 0 }, + {1919,1919, 0, 0, 40000, 46, 0, 0 }, + {1920,1920, 0, 0, 40000, 0, 0, 0 }, + {1921,1921, 0, 0, 40000, 53, 0, 0 }, + {1922,1922, 0, 0, 40000, 33, 0, 0 }, + {1923,1923, 0, 0, 2073, 193, 0, 0 }, + {1924,1924, 0, 0, 40000, 146, 0, 0 }, + {1925,1925, 0, 0, 40000, 100, 0, 0 }, + {1926,1926, 0, 0, 40000, 93, 0, 0 }, + {1927,1927, 0, 0, 40000, 73, 0, 0 }, + {1928,1928, 0, 0, 40000, 540, 0, 0 }, + {1929,1929, 0, 0, 40000, 520, 0, 0 }, + {1930,1930, 0, 0, 40000, 506, 0, 0 }, + {1931,1931, 0, 0, 7406, 200, 0, 0 }, + {1932,1932, 0, 0, 5906, 133, 0, 0 }, + {1933,1933, 0, 0, 7426, 240, 0, 0 }, + {1934,1934, 0, 0, 7426, 240, 0, 0 }, + {1935,1935, 0, 0, 40000, 66, 0, 0 }, + {1936,1936, 0, 0, 40000, 66, 0, 0 }, + {1937,1937, 0, 0, 40000, 53, 0, 0 }, + {1938,1938, 0, 0, 40000, 66, 0, 0 }, + {1939,1939, 0, 0, 40000, 66, 0, 0 }, + {1940,1940, 0, 0, 40000, 53, 0, 0 }, + {1941,1941, 0, 0, 40000, 2146, 0, 0 }, + {1942,1942, 0, 0, 40000, 1126, 0, 0 }, + {1943,1943, 0, 0, 40000, 1020, 0, 0 }, + {1944,1944, 0, 0, 40000, 433, 0, 0 }, + {1945,1945, 0, 0, 40000, 0, 0, 0 }, + {1946,1946, 0, 0, 40000, 140, 0, 0 }, + {1947,1947, 0, 0, 4660, 660, 0, 0 }, + {1948,1948, 0, 0, 40000, 66, 0, 0 }, + {1949,1949, 0, 0, 40000, 4193, 0, 0 }, + {1950,1950, 0, 0, 7713, 2466, 0, 0 }, + {1951,1951, 0, 0, 40000, 73, 0, 0 }, + {1952,1952, 0, 0, 8100, 2093, 0, 0 }, + {1953,1953, 0, 0, 40000, 86, 0, 0 }, + {1954,1954, 0, 0, 40000, 80, 0, 0 }, + {1955,1955, 0, 0, 4113, 1526, 0, 0 }, + {1956,1956, 0, 0, 40000, 66, 0, 0 }, + {1957,1957, 0, 0, 40000, 100, 0, 0 }, + {1958,1958, 0, 0, 40000, 213, 0, 0 }, + {1959,1959, 0, 0, 40000, 100, 0, 0 }, + {1960,1960, 0, 0, 1186, 100, 0, 0 }, + {1961,1961, 0, 0, 40000, 433, 0, 0 }, + {1962,1962, 0, 0, 40000, 146, 0, 0 }, + {1963,1963, 0, 0, 40000, 400, 0, 0 }, + {1964,1964, 0, 0, 40000, 66, 0, 0 }, + {1965,1965, 0, 0, 40000, 193, 0, 0 }, + {1966,1966, 0, 0, 1153, 100, 0, 0 }, + {1967,1967, 0, 0, 4800, 1400, 0, 0 }, + {1968,1968, 0, 0, 2906, 713, 0, 0 }, + {1969,1969, 0, 0, 40000, 73, 0, 0 }, + {1970,1970, 0, 0, 2280, 746, 0, 0 }, + {1971,1971, 0, 0, 40000, 66, 0, 0 }, + {1972,1972, 0, 0, 40000, 86, 0, 0 }, + {1973,1973, 0, 0, 40000, 86, 0, 0 }, + {1974,1974, 0, 0, 40000, 66, 0, 0 }, + {1975,1975, 0, 0, 40000, 66, 0, 0 }, + {1976,1976, 0, 0, 40000, 66, 0, 0 }, + {1977,1977, 0, 0, 40000, 46, 0, 0 }, + {1978,1978, 0, 0, 40000, 73, 0, 0 }, + {1979,1979, 0, 0, 40000, 73, 0, 0 }, + {1980,1980, 0, 0, 40000, 66, 0, 0 }, + {1981,1981, 0, 0, 40000, 66, 0, 0 }, + {1982,1982, 0, 0, 40000, 66, 0, 0 }, + {1983,1983, 0, 0, 40000, 73, 0, 0 }, + {1984,1984, 0, 0, 40000, 73, 0, 0 }, + {1985,1985, 0, 0, 40000, 253, 0, 0 }, + {1986,1986, 0, 0, 40000, 126, 0, 0 }, + {1987,1987, 0, 0, 40000, 126, 0, 0 }, + {1988,1988, 0, 0, 40000, 66, 0, 0 }, + {1989,1989, 0, 0, 40000, 66, 0, 0 }, + {1990,1990, 0, 0, 40000, 53, 0, 0 }, + {1991,1991, 0, 0, 40000, 140, 0, 0 }, + {1992,1992, 0, 0, 40000, 40, 0, 0 }, + {1993,1993, 0, 0, 40000, 73, 0, 0 }, + {1994,1994, 0, 0, 40000, 66, 0, 0 }, + {1995,1995, 0, 0, 40000, 73, 0, 0 }, + {1996,1996, 0, 0, 40000, 73, 0, 0 }, + {1997,1997, 0, 0, 40000, 73, 0, 0 }, + {1998,1998, 0, 0, 40000, 73, 0, 0 }, + {1999,1999, 0, 0, 40000, 66, 0, 0 }, + {2000,2000, 0, 0, 40000, 433, 0, 0 }, + {2001,2001, 0, 0, 40000, 433, 0, 0 }, + {2002,2002, 0, 0, 2440, 706, 0, 0 }, + {2003,2003, 0, 0, 13960, 4800, 0, 0 }, + {2004,2004, 0, 0, 7393, 2480, 0, 0 }, + {2005,2005, 0, 0, 7220, 2073, 0, 0 }, + {2006,2006, 0, 0, 633, 233, 0, 0 }, + {2007,2007, 0, 0, 2326, 780, 0, 0 }, + {2008,2008, 0, 0, 40000, 73, 0, 0 }, + {2009,2009, 0, 0, 40000, 106, 0, 0 }, + {2010,2010, 0, 0, 40000, 126, 0, 0 }, + {2011,2011, 0, 0, 40000, 386, 0, 0 }, + {2012,2012, 0, 0, 40000, 66, 0, 0 }, + {2013,2013, 0, 0, 6893, 1273, 0, 0 }, + {2014,2014, 0, 0, 2546, 633, 0, 0 }, + {2015,2015, 0, 0, 206, 106, 0, 0 }, + {2016,2016, 0, 0, 213, 113, 0, 0 }, + {2017,2017, 0, 0, 360, 140, 0, 0 }, + {2018,2018, 0, 0, 1013, 193, 0, 0 }, + {2019,2019, 0, 0, 266, 66, 0, 0 }, + {2020,2020, 0, 0, 1880, 660, 0, 0 }, + {2021,2021, 0, 0, 286, 206, 0, 0 }, + {2022,2022, 0, 0, 3706, 1353, 0, 0 }, + {2023,2023, 0, 0, 1106, 380, 0, 0 }, + {2024,2024, 0, 0, 13220, 2466, 0, 0 }, + {2025,2025, 0, 0, 333, 26, 0, 0 }, + {2026,2026, 0, 0, 7346, 2440, 0, 0 }, + {2027,2027, 0, 0, 1273, 453, 0, 0 }, + { 352, 352, 51, 2, 6, 0, 0, 0 }, + {2028,2028, 35, 0, 700, 253, 0, 0 }, + {2028,2028, 36, 0, 706, 266, 0, 0 }, + {2029,2029, 47, 0, 100, 33, 0, 0 }, + {2030,2030, 38, 0, 346, 140, 0, 0 }, + {2019,2019, 39, 0, 220, 106, 0, 0 }, + {2031,2031, 45, 0, 286, 133, 0, 0 }, + { 492, 492, 41, 0, 1040, 406, 0, 0 }, + {2032,2032, 42, 0, 220, 106, 0, 0 }, + {2033,2033, 44, 0, 500, 193, 0, 0 }, + { 492, 492, 48, 0, 833, 346, 0, 0 }, + {2034,2034, 46, 0, 1866, 646, 0, 0 }, + { 492, 492, 53, 0, 873, 386, 0, 0 }, + { 167, 167, 56, 0, 646, 353, 0, 0 }, + {2035,2035, 61, 0, 366, 146, 0, 0 }, + {2036,2036, 56, 0, 1346, 473, 0, 0 }, + {2037,2037, 60, 0, 213, 126, 0, 0 }, + { 144, 144, 59, 0, 213, 126, 0, 0 }, + {2038,2038, 59, 0, 106, 40, 0, 0 }, + { 169, 169, 51, 0, 380, 366, 0, 0 }, + { 169, 169, 45, 0, 380, 366, 0, 0 }, + {2039,2039, 72, 0, 246, 20, 0, 0 }, + {2040,2040, 60, 0, 280, 20, 0, 0 }, + {2041,2041, 58, 0, 373, 360, 0, 0 }, + {2042,2042, 53, 0, 380, 366, 0, 0 }, + {2043,2043, 73, 0, 120, 26, 0, 0 }, + { 158, 158, 75, 0, 126, 140, 0, 0 }, + {2044,2044, 0, 0, 6786, 1073, 0, 0 }, + {2045,2045, 0, 0, 2046, 473, 0, 0 }, + {2046,2046, 0, 0, 3746, 1273, 0, 0 }, + {2047,2047, 0, 0, 1200, 3086, 0, 0 }, + {2048,2048, 0, 0, 1200, 3080, 0, 0 }, + {2049,2049, 0, 0, 40000, 2453, 0, 0 }, + {2050,2050, 0, 0, 40000, 413, 0, 0 }, + {2051,2051, 0, 0, 980, 2553, 0, 0 }, + {2052,2052, 0, 0, 40000, 2420, 0, 0 }, + {2053,2053, 0, 0, 40000, 2506, 0, 0 }, + {2054,2054, 0, 0, 40000, 380, 0, 0 }, + {2055,2055, 0, 0, 40000, 660, 0, 0 }, + {2056,2056, 0, 0, 40000, 73, 0, 0 }, + {2057,2057, 0, 0, 40000, 333, 0, 0 }, + {2058,2058, 0, 0, 833, 146, 0, 0 }, + {2059,2059, 0, 0, 1686, 620, 0, 0 }, + {2060,2060, 0, 0, 40000, 73, 0, 0 }, + {2061,2061, 0, 0, 40000, 0, 0, 0 }, + {2062,2062, 0, 0, 1873, 633, 0, 0 }, + {2063,2063, 0, 0, 40000, 380, 0, 0 }, + {2064,2064, 0, 0, 366, 286, 0, 0 }, + {2065,2065, 0, 0, 8866, 1366, 0, 0 }, + {2066,2066, 0, 0, 40000, 1513, 0, 0 }, + {2067,2067, 0, 0, 40000, 333, 0, 0 }, + {2068,2068, 0, 0, 9600, 1573, 0, 0 }, + {2069,2069, 0, 0, 3293, 746, 0, 0 }, + {2070,2070, 0, 0, 40000, 53, 0, 0 }, + {2071,2071, 0, 0, 40000, 73, 0, 0 }, + {2072,2072, 0, 0, 40000, 73, 0, 0 }, + {2073,2073, 0, 0, 40000, 240, 0, 0 }, + {2074,2074, 0, 0, 40000, 240, 0, 0 }, + {2075,2075, 0, 0, 40000, 140, 0, 0 }, + {2076,2076, 0, 0, 40000, 113, 0, 0 }, + {2077,2077, 0, 0, 40000, 240, 0, 0 }, + {2078,2078, 0, 0, 3613, 1146, 0, 0 }, + {2079,2079, 0, 0, 40000, 126, 0, 0 }, + {2080,2080, 0, 0, 40000, 0, 0, 0 }, + {2081,2081, 0, 0, 40000, 633, 0, 0 }, + {2082,2082, 0, 0, 40000, 453, 0, 0 }, + {2083,2083, 0, 0, 40000, 1146, 0, 0 }, + {2084,2084, 0, 0, 40000, 3600, 0, 0 }, + {2085,2085, 0, 0, 40000, 1586, 0, 0 }, + {2086,2086, 0, 0, 40000, 1586, 0, 0 }, + {2087,2087, 0, 0, 40000, 1586, 0, 0 }, + {2088,2088, 0, 0, 40000, 1646, 0, 0 }, + {2089,2089, 0, 0, 40000, 1580, 0, 0 }, + {2090,2090, 0, 0, 40000, 4393, 0, 0 }, + {2091,2091, 0, 0, 40000, 4540, 0, 0 }, + {2092,2092, 0, 0, 21373, 6160, 0, 0 }, + {2093,2093, 0, 0, 40000, 633, 0, 0 }, + {2094,2094, 0, 0, 18420, 6146, 0, 0 }, + {2095,2095, 0, 0, 2306, 813, 0, 0 }, + {2096,2096, 0, 0, 2813, 333, 0, 0 }, + {2097,2097, 0, 0, 3106, 600, 0, 0 }, + {2098,2098, 0, 0, 1026, 1580, 0, 0 }, + {2099,2099, 0, 0, 1873, 346, 0, 0 }, + {2100,2100, 0, 0, 40000, 73, 0, 0 }, + {2101,2101, 0, 0, 40000, 73, 0, 0 }, + {2102,2102, 0, 0, 1200, 1906, 0, 0 }, + {2103,2103, 0, 0, 980, 1313, 0, 0 }, + {2104,2104, 0, 0, 200, 20, 0, 0 }, + {2105,2105, 0, 0, 640, 253, 0, 0 }, + {2106,2106, 0, 0, 3120, 240, 0, 0 }, + {2107,2107, 0, 0, 753, 146, 0, 0 }, + {2108,2108, 0, 0, 40000, 3060, 0, 0 }, + {2109,2109, 0, 0, 40000, 233, 0, 0 }, + {2110,2110, 0, 0, 40000, 246, 0, 0 }, + {2111,2111, 0, 0, 40000, 240, 0, 0 }, + { 752, 752, 60, 0, 173, 20, 0, 0 }, + { 755, 755, 12, 0, 626, 240, 0, 0 }, + {2112,2112, 89, 0, 113, 26, 0, 0 }, + {2113,2113, 89, 0, 700, 266, 0, 0 }, + { 755, 755, 14, 0, 626, 240, 0, 0 }, + { 755, 755, 16, 0, 626, 246, 0, 0 }, + {2114,2114, 84, 0, 1593, 553, 0, 0 }, + { 755, 755, 19, 0, 626, 240, 0, 0 }, + {2115,2115, 38, 0, 220, 166, 0, 0 }, + {2116,2116, 36, 0, 1686, 760, 0, 0 }, + { 755, 755, 28, 0, 626, 240, 0, 0 }, + { 755, 755, 26, 0, 626, 240, 0, 0 }, + { 755, 755, 35, 0, 633, 246, 0, 0 }, + { 755, 755, 30, 0, 626, 240, 0, 0 }, + {2117,2117, 60, 0, 180, 53, 0, 0 }, + {2104,2104, 60, 0, 173, 20, 0, 0 }, + {2104,2104, 55, 0, 173, 20, 0, 0 }, + { 730, 730, 94, 0, 1886, 660, 0, 0 }, + {2118,2118, 0, 0, 1226, 73, 0, 0 }, + {2119,2119, 0, 0, 40000, 0, 0, 0 }, + {2120,2120, 0, 0, 40000, 146, 0, 0 }, + {2121,2121, 0, 0, 40000, 80, 0, 0 }, + {2122,2122, 0, 0, 40000, 80, 0, 0 }, + {2123,2123, 0, 0, 40000, 0, 0, 0 }, + {2124,2124, 0, 0, 40000, 126, 0, 0 }, + {2125,2125, 0, 0, 40000, 213, 0, 0 }, + {2126,2126, 0, 0, 40000, 80, 0, 0 }, + {2127,2127, 0, 0, 40000, 73, 0, 0 }, + {2128,2128, 0, 0, 40000, 73, 0, 0 }, + {2129,2129, 0, 0, 40000, 73, 0, 0 }, + {2130,2130, 0, 0, 40000, 80, 0, 0 }, + {2131,2131, 0, 0, 40000, 73, 0, 0 }, + {2132,2132, 0, 0, 40000, 73, 0, 0 }, + {2133,2133, 0, 0, 40000, 66, 0, 0 }, + {2134,2134, 0, 0, 40000, 186, 0, 0 }, + {2135,2135, 0, 0, 9966, 426, 0, 0 }, + {2136,2136, 0, 0, 40000, 400, 0, 0 }, + {2137,2137, 0, 0, 40000, 326, 0, 0 }, + {2138,2138, 0, 0, 386, 80, 0, 0 }, + {2139,2139, 0, 0, 40000, 246, 0, 0 }, + {2140,2140, 0, 0, 3473, 73, 0, 0 }, + {2141,2141, 60, 0, 160, 66, 0, 0 }, + {2141,2141, 44, 0, 160, 60, 0, 0 }, + {2142,2142, 47, 0, 173, 93, 0, 0 }, + {2143,2143, 47, 0, 186, 80, 0, 0 }, + {2144,2144, 62, 0, 1933, 93, 0, 0 }, + {2145,2145, 93, 0, 1146, 473, 0, 0 }, + {2146,2146, 50, 0, 286, 93, 0, 0 }, + {2145,2145, 40, 0, 2013, 840, 0, 0 }, + {2147,2147, 60, 0, 106, 73, 0, 0 }, + { 898, 898, 60, 0, 173, 133, 0, 0 }, + {2147,2147, 57, 0, 106, 73, 0, 0 }, + { 900, 900, 42, 0, 620, 240, 0, 0 }, + { 900, 900, 38, 0, 626, 240, 0, 0 }, + { 908, 908, 88, 0, 160, 26, 0, 0 }, + {2148,2148, 0, 0, 9440, 140, 0, 0 }, + {2149,2149, 0, 0, 40000, 73, 0, 0 }, + {2150,2150, 0, 0, 4613, 420, 0, 0 }, + {2151,2151, 0, 0, 40000, 86, 0, 0 }, + {2152,2152, 0, 0, 40000, 406, 0, 0 }, + {2153,2153, 0, 0, 40000, 440, 0, 0 }, + {2154,2154, 0, 0, 4340, 133, 0, 0 }, + {2155,2155, 0, 0, 4460, 706, 0, 0 }, + {2156,2156, 0, 0, 40000, 73, 0, 0 }, + {2157,2157, 0, 0, 4660, 1573, 0, 0 }, + {2158,2158, 0, 0, 966, 333, 0, 0 }, + {2159,2159, 0, 0, 1933, 640, 0, 0 }, + { 136, 136, 0, 0, 2326, 786, 0, 0 }, + { 168, 168, 0, 0, 286, 366, 0, 0 }, + { 164, 164, 0, 0, 7373, 2460, 0, 0 }, + { 167, 167, 0, 0, 793, 426, 0, 0 }, + {2160,2160, 65, 0, 166, 73, 0, 0 }, + {2161,2161, 21, 0, 480, 146, 0, 0 }, + {2162, 173, 0, 4, 4220, 80, 0, 0 }, + {2163,2164, 0, 4, 4613, 3060, 0, 0 }, + {2165,2166, 0, 4, 7193, 3920, 0, 0 }, + {2167,2168, 0, 4, 3746, 1253, 0, 0 }, + {2169,2170, 0, 4, 6226, 2393, 0, 0 }, + {2171,2172, 0, 4, 18053, 226, 0, 0 }, + {2173,2174, 0, 4, 40000, 713, 0, 0 }, + {2175,2174, 0, 4, 40000, 733, 0, 0 }, + {2176, 299, 0, 4, 40000, 273, 0, 0 }, + {2177,2178, 0, 4, 40000, 66, 0, 0 }, + {2179,2180, 0, 4, 40000, 393, 0, 0 }, + {2181,2182, 0, 4, 40000, 413, 0, 0 }, + {2183,2184, 0, 4, 7366, 200, 0, 0 }, + { 127, 127, 65, 0, 226, 120, 0, 0 }, + { 127, 127, 72, 0, 180, 100, 0, 0 }, + { 364, 365, 52, 4, 120, 26, 0, 0 }, + {2185,2186, 60, 4, 173, 93, 0, 0 }, + {1550,1551, 47, 4, 520, 213, 0, 0 }, + {1556,1557, 76, 4, 766, 306, 0, 0 }, + { 374, 375, 84, 4, 813, 300, 0, 0 }, + {1564,1565, 83, 4, 220, 106, 0, 0 }, + {1568,1569, 24, 4, 1806, 620, 0, 0 }, + {1556,1557, 77, 4, 760, 300, 0, 0 }, + {1572,1573, 60, 4, 280, 126, 0, 0 }, + {1574,1575, 65, 4, 286, 193, 0, 0 }, + { 391, 392, 44, 4, 160, 53, 0, 0 }, + { 391, 393, 40, 4, 460, 66, 0, 0 }, + {1606,1607, 72, 4, 120, 73, 0, 0 }, + { 398, 399, 73, 4, 1286, 173, 0, 0 }, + {1608,1609, 70, 4, 1560, 300, 0, 0 }, + {2187,2187, 0, 0, 40000, 353, 0, 0 }, + {2188,2188, 0, 0, 40000, 333, 0, 0 }, + {2189,2189, 0, 0, 5913, 2306, 0, 0 }, + {2190,2190, 0, 0, 7720, 1260, 0, 0 }, + {2191,2191, 0, 0, 213, 6420, 0, 0 }, + {2192,2192, 0, 0, 40000, 380, 0, 0 }, + {2193,2193, 0, 0, 1153, 760, 0, 0 }, + {2194,2194, 0, 0, 40000, 66, 0, 0 }, + {2195,2195, 0, 0, 4440, 66, 0, 0 }, + {2196,2196, 0, 0, 40000, 73, 0, 0 }, + {2197,2197, 0, 0, 40000, 53, 0, 0 }, + {2198,2198, 0, 0, 40000, 60, 0, 0 }, + {2199,2199, 0, 0, 40000, 60, 0, 0 }, + {2200,2200, 0, 0, 8133, 1433, 0, 0 }, + { 528, 528, 0, 0, 966, 346, 0, 0 }, + {2201,2201, 0, 0, 40000, 126, 0, 0 }, + {2202,2202, 0, 0, 286, 1293, 0, 0 }, + {2203,2203, 0, 0, 40000, 0, 0, 0 }, + {2204,2204, 41, 0, 246, 20, 0, 0 }, + {2205,2205, 84, 0, 160, 26, 0, 0 }, + {2206,2206, 72, 0, 440, 180, 0, 0 }, + { 741, 741, 48, 0, 220, 26, 0, 0 }, + {2207,2207, 0, 0, 2126, 173, 0, 0 }, + {2208,2208, 0, 0, 40000, 0, 0, 0 }, + {2209,2209, 0, 0, 40000, 380, 0, 0 }, + {2210,2210, 0, 0, 4553, 1486, 0, 0 }, + {2211,2211, 0, 0, 40000, 73, 0, 0 }, + {2212,2212, 0, 0, 40000, 73, 0, 0 }, + {2213,2213, 0, 0, 1460, 80, 0, 0 }, + {2214,2214, 0, 0, 40000, 66, 0, 0 }, + {2215,2215, 0, 0, 40000, 186, 0, 0 }, + {2216,2216, 0, 0, 40000, 180, 0, 0 }, + {2217,2217, 0, 0, 40000, 173, 0, 0 }, + {2218,2218, 0, 0, 40000, 113, 0, 0 }, + {2219,2219, 0, 0, 40000, 86, 0, 0 }, + {2220,2220, 0, 0, 40000, 373, 0, 0 }, + {2221,2221, 0, 0, 40000, 113, 0, 0 }, + {2222,2222, 0, 0, 40000, 353, 0, 0 }, + {2223,2223, 0, 0, 40000, 66, 0, 0 }, + {2224,2224, 0, 0, 40000, 53, 0, 0 }, + {2225,2225, 0, 0, 40000, 66, 0, 0 }, + {2226,2226, 0, 0, 40000, 100, 0, 0 }, + {2227,2227, 0, 0, 40000, 73, 0, 0 }, + {2228,2228, 0, 0, 40000, 73, 0, 0 }, + {2229,2229, 0, 0, 40000, 66, 0, 0 }, + {2230,2230, 0, 0, 40000, 66, 0, 0 }, + {2231,2231, 0, 0, 40000, 80, 0, 0 }, + {2232,2232, 0, 0, 40000, 66, 0, 0 }, + {2233,2233, 0, 0, 40000, 80, 0, 0 }, + {2234,2234, 0, 0, 40000, 660, 0, 0 }, + {2235,2235, 0, 0, 40000, 120, 0, 0 }, + {2236,2236, 0, 0, 9820, 393, 0, 0 }, + {2237,2237, 0, 0, 40000, 73, 0, 0 }, + {2238,2238, 0, 0, 3620, 1166, 0, 0 }, + {2239,2239, 0, 0, 40000, 0, 0, 0 }, + {2240,2240, 0, 0, 40000, 0, 0, 0 }, + {2241,2241, 0, 0, 3020, 66, 0, 0 }, + {2242,2242, 0, 0, 6053, 1240, 0, 0 }, + {2243,2243, 0, 0, 633, 126, 0, 0 }, + {2244,2244, 0, 0, 40000, 66, 0, 0 }, + {2245,2245, 0, 0, 40000, 73, 0, 0 }, + {2246,2246, 0, 0, 626, 246, 0, 0 }, + {2247,2247, 60, 0, 173, 93, 0, 0 }, + {2248,2248, 60, 0, 673, 206, 0, 0 }, + {2249,2249, 48, 0, 673, 200, 0, 0 }, + {2250,2250, 60, 0, 1873, 653, 0, 0 }, + {2251,2251, 60, 0, 673, 200, 0, 0 }, + {2252,2252, 66, 0, 306, 120, 0, 0 }, + {2253,2253, 60, 0, 673, 200, 0, 0 }, + {2249,2249, 64, 0, 673, 206, 0, 0 }, + {2254,2254, 60, 0, 246, 106, 0, 0 }, + {2255,2255, 60, 0, 193, 120, 0, 0 }, + {2256,2256, 56, 0, 206, 13, 0, 0 }, + {2257,2257, 53, 0, 433, 73, 0, 0 }, + {2258,2258, 60, 0, 220, 113, 0, 0 }, + {2259,2259, 48, 0, 300, 66, 0, 0 }, + {2260,2260, 67, 0, 273, 60, 0, 0 }, + {2261,2261, 60, 0, 973, 360, 0, 0 }, + {2261,2261, 72, 0, 806, 273, 0, 0 }, + {2262,2262, 60, 0, 173, 93, 0, 0 }, + {2263,2263, 0, 0, 2493, 866, 0, 0 }, + {2264,2264, 24, 0, 173, 93, 0, 0 }, + {2265,2265, 36, 0, 140, 66, 0, 0 }, + { 343, 343, 36, 0, 146, 80, 0, 0 }, + { 347, 347, 0, 0, 353, 133, 0, 0 }, + { 347, 347, 12, 0, 420, 146, 0, 0 }, + {2266,2266, 12, 0, 346, 100, 0, 0 }, + {2267,2267, 24, 0, 106, 46, 0, 0 }, + {2267,2267, 36, 0, 100, 40, 0, 0 }, + {2268,2268, 0, 0, 1006, 293, 0, 0 }, + {2266,2266, 24, 0, 293, 93, 0, 0 }, + {2269,2269, 88, 0, 1106, 120, 0, 0 }, + {2270,2270, 88, 0, 666, 120, 0, 0 }, + {2271,2271, 13, 0, 760, 360, 0, 0 }, + { 351, 351, 0, 0, 966, 346, 0, 0 }, + {2271,2271, 15, 0, 760, 420, 0, 0 }, + {2272,2272, 0, 0, 4513, 640, 0, 0 }, + {2273,2273, 0, 0, 15486, 1580, 0, 0 }, + {2274,2274, 0, 0, 6940, 66, 0, 0 }, + {2275,2275, 0, 0, 6866, 2380, 0, 0 }, + {2276,2276, 0, 0, 7613, 1566, 0, 0 }, + {2277,2277, 0, 0, 1186, 420, 0, 0 }, + {2278,2278, 0, 0, 1166, 400, 0, 0 }, + {2279,2279, 0, 0, 40000, 2940, 0, 0 }, + {2280,2280, 0, 0, 40000, 0, 0, 0 }, + {2281,2281, 0, 0, 18226, 786, 0, 0 }, + {2282,2282, 0, 0, 40000, 0, 0, 0 }, + {2283,2283, 0, 0, 713, 200, 0, 0 }, + {2284,2284, 0, 0, 40000, 126, 0, 0 }, + {2285,2285, 0, 0, 40000, 353, 0, 0 }, + {2286,2286, 0, 0, 40000, 333, 0, 0 }, + {2287,2287, 0, 0, 40000, 0, 0, 0 }, + {2288,2288, 0, 0, 40000, 0, 0, 0 }, + {2289,2289, 0, 0, 40000, 0, 0, 0 }, + {2290,2290, 0, 0, 40000, 0, 0, 0 }, + {2291,2291, 0, 0, 40000, 73, 0, 0 }, + {2292,2292, 0, 0, 40000, 66, 0, 0 }, + {2293,2293, 0, 0, 15893, 153, 0, 0 }, + {2294,2294, 0, 0, 40000, 253, 0, 0 }, + {2295,2295, 0, 0, 2813, 333, 0, 0 }, + {2296,2296, 0, 0, 40000, 3920, 0, 0 }, + {2297,2297, 79, 0, 113, 113, 0, 0 }, + {2297,2297, 72, 0, 126, 140, 0, 0 }, + {2298,2298, 72, 0, 100, 26, 0, 0 }, + {2298,2298, 79, 0, 100, 26, 0, 0 }, + { 554, 554, 60, 0, 400, 126, 0, 0 }, + {2299,2299, 72, 0, 793, 173, 0, 0 }, + {2300,2300, 84, 0, 226, 66, 0, 0 }, + { 555, 555, 66, 0, 113, 53, 0, 0 }, + {2301,2302, 35, 4, 2320, 800, 0, 0 }, + {2303,2304, 52, 4, 120, 26, 0, 0 }, + {2305,1548, 48, 4, 173, 93, 0, 0 }, + {1595,1595, 58, 0, 146, 166, 0, 0 }, + {2305,1548, 60, 4, 173, 93, 0, 0 }, + {2306,2307, 47, 4, 1886, 700, 0, 0 }, + {2306,2307, 43, 4, 1946, 740, 0, 0 }, + {2306,2307, 49, 4, 1873, 686, 0, 0 }, + {2306,2307, 51, 4, 1880, 706, 0, 0 }, + {2306,2307, 54, 4, 1900, 720, 0, 0 }, + {2306,2307, 57, 4, 1893, 720, 0, 0 }, + {2306,2307, 72, 4, 1586, 606, 0, 0 }, + {2306,2307, 60, 4, 1893, 720, 0, 0 }, + {2306,2307, 76, 4, 1586, 606, 0, 0 }, + {2306,2307, 84, 4, 1593, 613, 0, 0 }, + {2306,2307, 36, 4, 2380, 920, 0, 0 }, + {1560,2308, 65, 4, 293, 213, 0, 0 }, + {2309,2310, 84, 4, 1366, 306, 0, 0 }, + {1564,1564, 83, 0, 220, 113, 0, 0 }, + { 380, 381, 84, 4, 1580, 566, 0, 0 }, + {1568,1568, 24, 0, 1833, 613, 0, 0 }, + {2306,2307, 77, 4, 1586, 606, 0, 0 }, + {2311,2312, 60, 4, 280, 126, 0, 0 }, + {2313,2314, 65, 4, 506, 200, 0, 0 }, + {2315,2315, 59, 0, 106, 40, 0, 0 }, + {2316,2316, 51, 0, 386, 373, 0, 0 }, + {1612,1612, 45, 0, 393, 380, 0, 0 }, + {2317,2317, 71, 0, 446, 180, 0, 0 }, + {2318,2318, 60, 0, 280, 20, 0, 0 }, + {2319,2319, 58, 0, 393, 373, 0, 0 }, + {2320,2320, 53, 0, 393, 380, 0, 0 }, + { 397, 397, 64, 0, 220, 86, 0, 0 }, + {2321,2321, 71, 0, 106, 46, 0, 0 }, + {2322,2322, 61, 0, 986, 340, 0, 0 }, + {2323,2323, 61, 0, 1893, 633, 0, 0 }, + {2324, 392, 44, 4, 166, 46, 0, 0 }, + {2324, 393, 40, 4, 460, 60, 0, 0 }, + {1595,1595, 69, 0, 126, 140, 0, 0 }, + {1595,1595, 68, 0, 126, 140, 0, 0 }, + {1595,1595, 63, 0, 146, 166, 0, 0 }, + {2325,2326, 74, 4, 380, 106, 0, 0 }, + {2327,2328, 60, 4, 1020, 333, 0, 0 }, + {2329,2330, 80, 4, 453, 560, 0, 0 }, + {2331,2332, 64, 4, 1880, 640, 0, 0 }, + { 397, 397, 72, 0, 193, 80, 0, 0 }, + {2333,2334, 78, 4, 793, 306, 0, 0 }, + {1608,1609, 82, 4, 1560, 300, 0, 0 }, + {2315,2315, 48, 0, 106, 46, 0, 0 }, + {2316,2316, 53, 0, 386, 373, 0, 0 }, + {2335,2335, 0, 0, 3586, 1133, 0, 0 }, + {2336,2337, 0, 4, 1180, 420, 0, 0 }, + {2338,2339, 0, 4, 40000, 320, 0, 0 }, + {2340,2340, 0, 0, 8826, 1346, 0, 0 }, + {2341,2341, 0, 0, 3440, 753, 0, 0 }, + {2342,2342, 0, 0, 40000, 360, 0, 0 }, + {2343,2343, 0, 0, 40000, 413, 0, 0 }, + {2344,2345, 0, 4, 40000, 60, 0, 0 }, + {2346,2346, 0, 0, 40000, 60, 0, 0 }, + {2347,2348, 0, 4, 40000, 126, 0, 0 }, + {2349,2350, 0, 4, 40000, 73, 0, 0 }, + {2351,2352, 0, 4, 40000, 73, 0, 0 }, + {2353,2354, 0, 4, 40000, 86, 0, 0 }, + {2355,2356, 0, 4, 40000, 453, 0, 0 }, + {2357,2357, 14, 0, 186, 20, 0, 0 }, + {2358,2358, 35, 0, 246, 73, 0, 0 }, + {2357,2357, 19, 0, 166, 26, 0, 0 }, + {2359,2359, 43, 0, 286, 133, 0, 0 }, + {2360,2360, 41, 0, 300, 113, 0, 0 }, + {2360,2360, 43, 0, 253, 106, 0, 0 }, + {2360,2360, 45, 0, 240, 100, 0, 0 }, + {2360,2360, 47, 0, 240, 100, 0, 0 }, + {2361,2362, 0, 4, 14633, 333, 0, 0 }, + {2363,2363, 0, 0, 7373, 1246, 0, 0 }, + {2364,2364, 0, 0, 4900, 233, 0, 0 }, + {2365,2365, 0, 0, 5106, 606, 0, 0 }, + {2366,2366, 0, 0, 1333, 153, 0, 0 }, + {2367,2367, 0, 0, 2093, 840, 0, 0 }, + {2368,2368, 0, 0, 3700, 226, 0, 0 }, + {2369,2369, 0, 0, 3546, 1266, 0, 0 }, + {2370,2370, 0, 0, 4606, 420, 0, 0 }, + {2371,2371, 0, 0, 14366, 606, 0, 0 }, + {2372,2372, 0, 0, 40000, 426, 0, 0 }, + {2373,2373, 0, 0, 3700, 200, 0, 0 }, + {2374,2374, 0, 0, 880, 440, 0, 0 }, + {2375,2375, 0, 0, 4660, 660, 0, 0 }, + {2376,2376, 0, 0, 3600, 1153, 0, 0 }, + {2377,2377, 0, 0, 40000, 73, 0, 0 }, + {2378,2378, 0, 0, 40000, 53, 0, 0 }, + {2379,2379, 0, 0, 40000, 333, 0, 0 }, + {2380,2380, 0, 0, 40000, 73, 0, 0 }, + {2381,2381, 0, 0, 40000, 73, 0, 0 }, + {2382,2382, 0, 0, 40000, 66, 0, 0 }, + {2383,2383, 0, 0, 40000, 73, 0, 0 }, + {2384,2384, 0, 0, 40000, 73, 0, 0 }, + {2385,2385, 0, 0, 840, 226, 0, 0 }, + {2386,2386, 0, 0, 2093, 86, 0, 0 }, + {2387,2387, 0, 0, 906, 73, 0, 0 }, + { 402, 402, 0, 0, 273, 60, 0, 0 }, + {2388,2388, 0, 0, 40000, 820, 0, 0 }, + {2389,2389, 0, 0, 4740, 93, 0, 0 }, + {2390,2390, 0, 0, 706, 106, 0, 0 }, + {2391,2391, 0, 0, 40000, 0, 0, 0 }, + {2392,2392, 0, 0, 3840, 2306, 0, 0 }, + {2393,2393, 0, 0, 3400, 493, 0, 0 }, + {2394,2394, 0, 0, 40000, 53, 0, 0 }, + {2395,2395, 0, 0, 40000, 133, 0, 0 }, + {2396,2397, 0, 4, 3066, 1400, 0, 0 }, + {2398,2398, 0, 0, 1080, 580, 0, 0 }, + {2399,2400, 0, 4, 2220, 400, 0, 0 }, + {2401,2401, 0, 0, 40000, 193, 0, 0 }, + {2402,2402, 0, 0, 40000, 60, 0, 0 }, + {2403,2404, 0, 4, 40000, 146, 0, 0 }, + {2405,2406, 0, 4, 40000, 133, 0, 0 }, + {2407,2408, 0, 4, 40000, 66, 0, 0 }, + {2409,2409, 0, 0, 40000, 0, 0, 0 }, + {2410,2410, 0, 0, 40000, 73, 0, 0 }, + {2411,2411, 0, 0, 40000, 66, 0, 0 }, + {2412,2413, 0, 4, 40000, 153, 0, 0 }, + {2414,2414, 0, 0, 40000, 126, 0, 0 }, + {2415,2416, 0, 4, 40000, 466, 0, 0 }, + {2417,2418, 0, 4, 40000, 113, 0, 0 }, + {2419,2420, 0, 4, 1280, 73, 0, 0 }, + {2421,2422, 0, 4, 1106, 146, 0, 0 }, + {2423,2424, 0, 4, 3640, 113, 0, 0 }, + {2425,2426, 0, 4, 40000, 80, 0, 0 }, + {2427,2427, 33, 0, 300, 246, 0, 0 }, + {2428,2429, 38, 4, 53, 26, 0, 0 }, + {2430,2430, 38, 0, 106, 46, 0, 0 }, + {2431,2431, 38, 0, 340, 20, 0, 0 }, + {2432,2432, 40, 0, 73, 40, 0, 0 }, + {2433,2434, 41, 4, 293, 106, 0, 0 }, + {2435,2435, 0, 0, 133, 73, 0, 0 }, + {2435,2435, 41, 0, 133, 73, 0, 0 }, + {2360,2360, 48, 0, 240, 100, 0, 0 }, + {2436,2436, 17, 0, 4620, 1553, 0, 0 }, + {2360,2360, 50, 0, 240, 100, 0, 0 }, + {2435,2435, 45, 0, 126, 66, 0, 0 }, + {2437,2437,254, 2, 6, 0, 0, 0 }, + {2438,2438, 60, 0, 226, 93, 0, 0 }, + {2439,2439, 56, 0, 233, 93, 0, 0 }, + {2440,2440, 60, 0, 140, 66, 0, 0 }, + {2440,2440, 55, 0, 140, 60, 0, 0 }, + {2441,2441, 63, 0, 286, 126, 0, 0 }, + {2442,2442, 57, 0, 173, 93, 0, 0 }, + {2443,2443, 0, 0, 40000, 280, 0, 0 }, + {2444,2444, 0, 0, 40000, 0, 0, 0 }, + {2445,2445, 0, 0, 40000, 746, 0, 0 }, + {2446,2446, 0, 0, 40000, 353, 0, 0 }, + {2447,2447, 0, 0, 40000, 1173, 0, 0 }, + {2448,2448, 0, 0, 40000, 146, 0, 0 }, + {2449,2449, 0, 0, 40000, 1160, 0, 0 }, + {2450,2450, 0, 0, 40000, 353, 0, 0 }, + {2451,2451, 0, 0, 18313, 6046, 0, 0 }, + {2452,2452, 0, 0, 1206, 420, 0, 0 }, + { 752, 752, 55, 0, 173, 20, 0, 0 }, + {2453,2453, 0, 0, 2860, 806, 0, 0 }, + {2454,2454, 0, 0, 2506, 126, 0, 0 }, + {2455,2455, 0, 0, 520, 93, 0, 0 }, + {2456,2456, 0, 0, 1420, 160, 0, 0 }, + {2457,2457, 0, 0, 40000, 53, 0, 0 }, + {2458,2458, 0, 0, 9106, 100, 0, 0 }, + {2459,2459, 0, 0, 3706, 100, 0, 0 }, + {2460,2460, 0, 0, 17933, 100, 0, 0 }, + {2461,2461, 0, 0, 40000, 0, 0, 0 }, + {2462,2462, 0, 0, 40000, 66, 0, 0 }, + {2463,2463, 0, 0, 40000, 0, 0, 0 }, + { 884, 884, 0, 0, 306, 73, 0, 0 }, + { 884, 884, 28, 0, 306, 73, 0, 0 }, + {2464,2464, 29, 0, 226, 93, 0, 0 }, + { 886, 886, 31, 0, 113, 53, 0, 0 }, + { 360, 360, 32, 0, 133, 40, 0, 0 }, + { 361, 361, 33, 0, 286, 80, 0, 0 }, + {2453,2453, 34, 0, 2873, 813, 0, 0 }, + { 888, 888, 29, 0, 246, 46, 0, 0 }, + { 886, 886, 55, 0, 100, 33, 0, 0 }, + { 890, 890, 48, 0, 240, 60, 0, 0 }, + { 884, 884, 58, 0, 146, 26, 0, 0 }, + {2465,2465, 45, 0, 173, 93, 0, 0 }, + {2465,2465, 43, 0, 173, 93, 0, 0 }, + {2466,2466, 73, 0, 1633, 86, 0, 0 }, + {2467,2467, 72, 0, 866, 553, 0, 0 }, + {2468,2468, 76, 0, 1380, 620, 0, 0 }, + {2467,2467, 84, 0, 873, 560, 0, 0 }, + {2468,2468, 36, 0, 1933, 880, 0, 0 }, + {2469,2469, 65, 0, 300, 120, 0, 0 }, + {2470,2470, 83, 0, 193, 86, 0, 0 }, + {2471,2471, 50, 0, 966, 126, 0, 0 }, + {2468,2468, 77, 0, 1373, 620, 0, 0 }, + { 897, 897, 55, 0, 126, 40, 0, 0 }, + {2472,2472, 60, 0, 180, 140, 0, 0 }, + { 897, 897, 50, 0, 126, 40, 0, 0 }, + {2473,2473, 42, 0, 633, 240, 0, 0 }, + {2473,2473, 46, 0, 513, 200, 0, 0 }, + {2474,2474, 71, 0, 433, 180, 0, 0 }, + {2474,2474, 60, 0, 513, 206, 0, 0 }, + {2455,2455, 58, 0, 220, 46, 0, 0 }, + {2455,2455, 53, 0, 286, 60, 0, 0 }, + {2475,2475, 91, 0, 186, 100, 0, 0 }, + {2476,2476, 61, 0, 226, 26, 0, 0 }, + {2477,2477, 61, 0, 886, 73, 0, 0 }, + {2478,2478, 44, 0, 120, 73, 0, 0 }, + {2479,2479, 40, 0, 933, 73, 0, 0 }, + {2480,2480, 69, 0, 146, 33, 0, 0 }, + { 361, 361, 68, 0, 153, 26, 0, 0 }, + { 361, 361, 63, 0, 180, 26, 0, 0 }, + {2481,2481, 74, 0, 153, 73, 0, 0 }, + {2482,2482, 60, 0, 280, 100, 0, 0 }, + { 908, 908, 80, 0, 160, 26, 0, 0 }, + {2483,2483, 64, 0, 986, 353, 0, 0 }, + {2483,2483, 73, 0, 813, 306, 0, 0 }, + {2483,2483, 70, 0, 820, 306, 0, 0 }, + { 886, 886, 68, 0, 93, 33, 0, 0 }, + { 886, 886, 48, 0, 106, 40, 0, 0 }, + {2484,2484, 0, 0, 40000, 0, 0, 0 }, + {2485,2485, 0, 0, 3226, 753, 0, 0 }, + {2486,2486, 0, 0, 1773, 553, 0, 0 }, + {2487,2487, 0, 0, 7473, 2460, 0, 0 }, + {2488,2488, 0, 0, 40000, 0, 0, 0 }, + {2489,2489, 0, 0, 40000, 353, 0, 0 }, + {2490,2490, 0, 0, 40000, 206, 0, 0 }, + {2491,2491, 0, 0, 40000, 86, 0, 0 }, + {2492,2492, 0, 0, 4740, 86, 0, 0 }, + {2493,2493, 0, 0, 6193, 193, 0, 0 }, + {2494,2494, 0, 0, 6200, 240, 0, 0 }, + {2495,2495, 0, 0, 40000, 0, 0, 0 }, + {2496,2496, 0, 0, 1586, 73, 0, 0 }, + {2497,2497, 0, 0, 560, 73, 0, 0 }, + {2498,2498, 0, 0, 40000, 480, 0, 0 }, + {2499,2499, 0, 0, 40000, 80, 0, 0 }, + {2500,2500, 0, 0, 40000, 66, 0, 0 }, + {2501,2501, 0, 0, 40000, 380, 0, 0 }, + {2502,2502, 0, 0, 280, 100, 0, 0 }, + {2503,2503, 0, 0, 6193, 233, 0, 0 }, + {2504,2504, 0, 0, 40000, 380, 0, 0 }, + {2505,2505, 0, 0, 40000, 0, 0, 0 }, + {2506,2506, 0, 0, 40000, 380, 0, 0 }, + {2507,2507, 0, 0, 40000, 200, 0, 0 }, + {2508,2508, 0, 0, 40000, 320, 0, 0 }, + {2509,2509, 0, 0, 40000, 126, 0, 0 }, + {2510,2510, 0, 0, 40000, 293, 0, 0 }, + {2511,2511, 0, 0, 40000, 0, 0, 0 }, + {2512,2512, 0, 0, 40000, 40, 0, 0 }, + {2513,2513, 0, 0, 40000, 106, 0, 0 }, + {2514,2514, 0, 0, 3846, 73, 0, 0 }, + {2515,2515, 0, 0, 40000, 0, 0, 0 }, + {2516,2516, 0, 0, 40000, 73, 0, 0 }, + {2517,2517, 0, 0, 40000, 533, 0, 0 }, + {2518,2518, 0, 0, 40000, 1020, 0, 0 }, + {2519,2519, 0, 0, 40000, 73, 0, 0 }, + {2520,2520, 0, 0, 40000, 53, 0, 0 }, + {2521,2521, 0, 0, 6153, 1433, 0, 0 }, + {2522,2522, 0, 0, 18813, 773, 0, 0 }, + {2523,2523, 0, 0, 40000, 433, 0, 0 }, + {2524,2524, 0, 0, 40000, 0, 0, 0 }, + {2525,2525, 0, 0, 40000, 133, 0, 0 }, + {2526,2526, 0, 0, 4486, 73, 0, 0 }, + { 346, 346, 30, 0, 540, 33, 0, 0 }, + { 346, 346, 31, 0, 406, 20, 0, 0 }, + { 346, 346, 32, 0, 406, 20, 0, 0 }, + { 346, 346, 33, 0, 406, 73, 0, 0 }, + { 346, 346, 34, 0, 406, 20, 0, 0 }, + { 346, 346, 35, 0, 406, 20, 0, 0 }, + { 346, 346, 37, 0, 406, 73, 0, 0 }, + { 346, 346, 39, 0, 406, 73, 0, 0 }, + { 346, 346, 41, 0, 406, 20, 0, 0 }, + { 346, 346, 43, 0, 306, 20, 0, 0 }, + { 346, 346, 45, 0, 306, 20, 0, 0 }, + { 346, 346, 47, 0, 306, 20, 0, 0 }, + { 346, 346, 48, 0, 306, 20, 0, 0 }, + { 346, 346, 49, 0, 306, 20, 0, 0 }, + { 512, 512, 84, 0, 353, 466, 0, 0 }, + {2206,2206, 84, 0, 440, 180, 0, 0 }, + {2527,2527, 55, 0, 100, 0, 0, 0 }, + {2528,2528, 36, 0, 400, 160, 0, 0 }, + {2529,2529, 38, 0, 313, 226, 0, 0 }, + {2530,2530, 60, 0, 286, 133, 0, 0 }, + {2531,2531, 38, 0, 200, 100, 0, 0 }, + {2532,2532, 17, 0, 6186, 240, 0, 0 }, + {2532,2532, 18, 0, 6186, 240, 0, 0 }, + {2532,2532, 19, 0, 6193, 233, 0, 0 }, + {2532,2532, 20, 0, 6193, 193, 0, 0 }, + {2532,2532, 21, 0, 6193, 193, 0, 0 }, + {2532,2532, 22, 0, 6193, 193, 0, 0 }, + {2532,2532, 23, 0, 6193, 193, 0, 0 }, + {2532,2532, 24, 0, 6193, 193, 0, 0 }, + {2532,2532, 25, 0, 6193, 193, 0, 0 }, + {2532,2532, 26, 0, 6193, 193, 0, 0 }, + {2532,2532, 27, 0, 6193, 253, 0, 0 }, + {2532,2532, 28, 0, 6193, 246, 0, 0 }, + {2532,2532, 29, 0, 6193, 246, 0, 0 }, + {2533,2533, 84, 0, 433, 180, 0, 0 }, + {2534,2534, 48, 0, 280, 93, 0, 0 }, + {2535,2535, 65, 0, 1166, 360, 0, 0 }, + {2536,2536, 65, 0, 1853, 633, 0, 0 }, + {2537,2537, 55, 0, 453, 366, 0, 0 }, + {2537,2537, 41, 0, 540, 433, 0, 0 }, + { 346, 346, 63, 0, 240, 66, 0, 0 }, + { 346, 346, 55, 0, 240, 66, 0, 0 }, + {2538,2538, 55, 0, 2586, 200, 0, 0 }, + {2538,2538, 53, 0, 2586, 200, 0, 0 }, + {2534,2534, 50, 0, 280, 93, 0, 0 }, + { 506, 506, 84, 0, 693, 566, 0, 0 }, + { 506, 506, 74, 0, 693, 560, 0, 0 }, + { 504, 504, 84, 0, 1566, 546, 0, 0 }, + { 504, 504, 74, 0, 1586, 560, 0, 0 }, + {2539,2539, 84, 0, 440, 20, 0, 0 }, + {2540,2540, 74, 0, 126, 26, 0, 0 }, + {1911,1911, 48, 0, 500, 180, 0, 0 }, + {1911,1911, 36, 0, 606, 220, 0, 0 }, + {2541,2541, 74, 0, 686, 560, 0, 0 }, + {2542,2542, 0, 0, 7313, 13, 0, 0 }, + {2543,2543, 0, 0, 40000, 1306, 0, 0 }, + {2544,2544, 0, 0, 40000, 0, 0, 0 }, + {2545,2545, 0, 0, 4613, 13, 0, 0 }, + {2546,2547, 0, 4, 6926, 126, 0, 0 }, + {2548,2549, 0, 4, 40000, 86, 0, 0 }, + {2550,2550, 0, 0, 9233, 100, 0, 0 }, + {2551,2552, 0, 4, 4620, 73, 0, 0 }, + {2553,2553, 0, 0, 40000, 73, 0, 0 }, + {2554,2554, 0, 0, 40000, 0, 0, 0 }, + {2555,2556, 0, 4, 40000, 73, 0, 0 }, + {2557,2557, 0, 0, 40000, 60, 0, 0 }, + {2558,1467, 0, 4, 40000, 66, 0, 0 }, + {2559,2560, 0, 4, 40000, 40, 0, 0 }, + {2561,2561, 0, 0, 40000, 186, 0, 0 }, + {2562,2562, 0, 0, 4026, 66, 0, 0 }, + {2563,2564, 0, 4, 14513, 80, 0, 0 }, + {2565,2565, 0, 0, 40000, 0, 0, 0 }, + {2566,2567, 0, 4, 40000, 40, 0, 0 }, + {2568,2568, 0, 0, 4020, 73, 0, 0 }, + {2569,2569, 0, 0, 40000, 0, 0, 0 }, + {2570,2570, 0, 0, 40000, 0, 0, 0 }, + {2571,2572, 0, 4, 40000, 126, 0, 0 }, + {2573,2574, 0, 4, 40000, 100, 0, 0 }, + {2575,2575, 0, 0, 40000, 213, 0, 0 }, + { 229,2576, 0, 4, 40000, 166, 0, 0 }, + {2577,2577, 0, 0, 7366, 53, 0, 0 }, + { 239,2578, 0, 4, 40000, 133, 0, 0 }, + {2579,2579, 0, 0, 40000, 80, 0, 0 }, + {2580,2580, 0, 0, 40000, 140, 0, 0 }, + {2581,2582, 0, 4, 16913, 1173, 0, 0 }, + {2583,2584, 0, 4, 726, 100, 0, 0 }, + {2585,2586, 0, 4, 40000, 73, 0, 0 }, + {2587,2588, 0, 4, 40000, 73, 0, 0 }, + {2589,2589, 0, 0, 40000, 60, 0, 0 }, + {2590,2590, 0, 0, 40000, 80, 0, 0 }, + {2591,2592, 0, 4, 40000, 73, 0, 0 }, + {2593,2594, 0, 4, 40000, 60, 0, 0 }, + {2595,2595, 0, 0, 40000, 66, 0, 0 }, + {2596,2597, 0, 4, 40000, 66, 0, 0 }, + {2598,2599, 0, 4, 40000, 60, 0, 0 }, + {2600,2601, 0, 4, 40000, 173, 0, 0 }, + {2602,2602, 0, 0, 40000, 60, 0, 0 }, + {2603,2603, 0, 0, 40000, 73, 0, 0 }, + {2604,2604, 0, 0, 40000, 93, 0, 0 }, + {2605,2606, 0, 4, 40000, 73, 0, 0 }, + {2607,2607, 0, 0, 40000, 66, 0, 0 }, + {2608,2609, 0, 4, 40000, 66, 0, 0 }, + {2610,2610, 0, 0, 40000, 86, 0, 0 }, + {2611,2611, 0, 0, 40000, 60, 0, 0 }, + {2612,2612, 0, 0, 14286, 73, 0, 0 }, + {2613,2613, 0, 0, 40000, 0, 0, 0 }, + {2614,2615, 0, 4, 40000, 73, 0, 0 }, + {2616,2617, 0, 4, 40000, 66, 0, 0 }, + {2618,2619, 0, 4, 133, 26, 0, 0 }, + {2620,2621, 0, 4, 40000, 1280, 0, 0 }, + {2622,2623, 0, 4, 40000, 160, 0, 0 }, + {2624,2625, 0, 4, 40000, 0, 0, 0 }, + {2626,2627, 0, 4, 40000, 73, 0, 0 }, + {2628,2629, 0, 4, 40000, 0, 0, 0 }, + {1516,2630, 0, 4, 1186, 406, 0, 0 }, + {2631,2632, 0, 4, 40000, 553, 0, 0 }, + {2633,2633, 0, 0, 40000, 40, 0, 0 }, + {2634,2635, 0, 4, 40000, 773, 0, 0 }, + {2636,2636, 0, 0, 40000, 320, 0, 0 }, + {2637,2637, 0, 0, 1880, 73, 0, 0 }, + {2638,2639, 0, 4, 473, 186, 0, 0 }, + {2640,2641, 0, 4, 16946, 1193, 0, 0 }, + {2642,2642, 0, 0, 40000, 720, 0, 0 }, + {2643,2644, 0, 4, 1880, 40, 0, 0 }, + {2645,2645, 0, 0, 40000, 73, 0, 0 }, + {2646,2647, 0, 4, 40000, 46, 0, 0 }, + {2648,2648, 0, 0, 2466, 80, 0, 0 }, + {2649,2649, 0, 0, 40000, 193, 0, 0 }, + {2650,2651, 0, 4, 993, 73, 0, 0 }, + {2652,2652, 0, 0, 40000, 220, 0, 0 }, + {2653,2654, 0, 4, 40000, 46, 0, 0 }, + {2655,2656, 0, 4, 40000, 46, 0, 0 }, + {2657,2657, 0, 0, 40000, 66, 0, 0 }, + {2658,2658, 35, 0, 626, 20, 0, 0 }, + {2659,2659, 35, 0, 306, 26, 0, 0 }, + {2660,2660, 52, 0, 126, 26, 0, 0 }, + {2661,2661, 60, 0, 286, 20, 0, 0 }, + {2662,2662, 58, 0, 113, 26, 0, 0 }, + {2663,2663, 60, 0, 380, 20, 0, 0 }, + {2664,2664, 50, 0, 1640, 66, 0, 0 }, + {2665,2665, 43, 0, 153, 20, 0, 0 }, + {2664,2664, 55, 0, 1640, 20, 0, 0 }, + {1553,1553, 43, 0, 160, 80, 0, 0 }, + {2666,2666, 50, 0, 980, 20, 0, 0 }, + {2667,2667, 43, 0, 446, 73, 0, 0 }, + {2666,2666, 53, 0, 1000, 80, 0, 0 }, + {2666,2666, 57, 0, 700, 73, 0, 0 }, + {2668,2668, 72, 0, 773, 13, 0, 0 }, + {2666,2666, 60, 0, 686, 20, 0, 0 }, + { 373, 373, 76, 0, 826, 20, 0, 0 }, + {2669,2669, 84, 0, 713, 20, 0, 0 }, + {2670,2670, 42, 0, 1186, 20, 0, 0 }, + {2671,2671, 65, 0, 293, 33, 0, 0 }, + {2672,2672, 84, 0, 386, 33, 0, 0 }, + {2673,2673, 84, 0, 1366, 20, 0, 0 }, + {2674,2674, 24, 0, 960, 73, 0, 0 }, + { 383, 383, 77, 0, 800, 20, 0, 0 }, + {2675,2675, 58, 0, 426, 26, 0, 0 }, + {2676,2676, 53, 0, 426, 20, 0, 0 }, + {2677,2677, 64, 0, 200, 66, 0, 0 }, + {2678,2678, 71, 0, 113, 13, 0, 0 }, + {2679,2679, 44, 0, 766, 66, 0, 0 }, + {2680,2680, 40, 0, 460, 60, 0, 0 }, + {2681,2681, 69, 0, 126, 26, 0, 0 }, + {2682,2682, 60, 0, 573, 66, 0, 0 }, + {2683,2683, 80, 0, 226, 20, 0, 0 }, + {2684,2684, 64, 0, 2693, 20, 0, 0 }, + {2685,2685, 72, 0, 120, 66, 0, 0 }, + {2686,2686, 70, 0, 820, 20, 0, 0 }, + {2687,2687, 48, 0, 173, 20, 0, 0 }, + {2688,2688, 53, 0, 980, 33, 0, 0 }, + {2689,2690, 0, 4, 40000, 286, 0, 0 }, + {2691,2692, 0, 4, 2326, 100, 0, 0 }, + {2693,2694, 0, 4, 380, 80, 0, 0 }, + {2695,2696, 0, 4, 14766, 73, 0, 0 }, + {2697,2698, 0, 4, 40000, 40, 0, 0 }, + { 192,2699, 0, 4, 40000, 73, 0, 0 }, + {2700,2701, 0, 4, 973, 126, 0, 0 }, + {2702,2703, 0, 4, 4626, 106, 0, 0 }, + {2704,2705, 0, 4, 40000, 73, 0, 0 }, + {2706,2707, 0, 4, 40000, 73, 0, 0 }, + {2708,2709, 0, 4, 40000, 73, 0, 0 }, + {2710,2711, 0, 4, 2053, 93, 0, 0 }, + {2712,1473, 0, 4, 320, 26, 0, 0 }, + {2713,2714, 0, 4, 573, 93, 0, 0 }, + {2715,2716, 0, 4, 6466, 353, 0, 0 }, + {1478,2717, 0, 4, 40000, 146, 0, 0 }, + {2718,2719, 0, 4, 40000, 66, 0, 0 }, + { 286,2720, 0, 4, 40000, 73, 0, 0 }, + {2721,2722, 0, 4, 40000, 86, 0, 0 }, + {2723,2724, 0, 4, 40000, 60, 0, 0 }, + {2725,2726, 0, 4, 393, 73, 0, 0 }, + {2727,2724, 0, 4, 40000, 60, 0, 0 }, + {1514,2728, 0, 4, 40000, 180, 0, 0 }, + {2729,2730, 0, 4, 40000, 0, 0, 0 }, + {2731,2732, 0, 4, 473, 186, 0, 0 }, + {2733,2734, 0, 4, 733, 33, 0, 0 }, + {2735,2736, 0, 4, 286, 40, 0, 0 }, + {2737,2738, 0, 4, 40000, 73, 0, 0 }, + {2739,2740, 0, 4, 1313, 746, 0, 0 }, + {2741,2742, 0, 4, 1326, 700, 0, 0 }, + {2743,2744, 0, 4, 40000, 0, 0, 0 }, + {2745,2746, 0, 4, 2046, 73, 0, 0 }, + {2747,2747, 35, 0, 386, 166, 0, 0 }, + {2748,2748, 60, 0, 493, 193, 0, 0 }, + {2749,2749, 43, 0, 126, 66, 0, 0 }, + {2750,2750, 0, 0, 3740, 1260, 0, 0 }, + {2751,2752, 0, 4, 14833, 360, 0, 0 }, + {2753,2754, 0, 4, 10206, 273, 0, 0 }, + {2755,2756, 0, 4, 18033, 146, 0, 0 }, + {2757,2758, 0, 4, 14433, 326, 0, 0 }, + {2759,2760, 0, 4, 14580, 626, 0, 0 }, + {2761,2762, 0, 4, 14720, 300, 0, 0 }, + {2763,2764, 0, 4, 10426, 106, 0, 0 }, + {2765,2766, 0, 4, 40000, 60, 0, 0 }, + {2767,2768, 0, 4, 40000, 80, 0, 0 }, + {2769,2770, 0, 4, 40000, 80, 0, 0 }, + {2771,2772, 0, 4, 40000, 73, 0, 0 }, + {2773,2774, 0, 4, 40000, 73, 0, 0 }, + {2775,2776, 0, 4, 40000, 80, 0, 0 }, + {2777,2778, 0, 4, 40000, 73, 0, 0 }, + {2779,2780, 0, 4, 40000, 73, 0, 0 }, + {2781,2782, 0, 4, 40000, 66, 0, 0 }, + {2783,2784, 0, 4, 7220, 186, 0, 0 }, + {2785,2786, 0, 4, 10300, 113, 0, 0 }, + {2787,2788, 0, 4, 40000, 246, 0, 0 }, + {2789,2790, 0, 4, 9106, 746, 0, 0 }, + {2791,2792, 0, 4, 7373, 666, 0, 0 }, + {2793,2794, 0, 4, 1200, 426, 0, 0 }, + {2795,2796, 0, 4, 40000, 413, 0, 0 }, + {2795,2797, 0, 4, 40000, 1506, 0, 0 }, + {2798,2799, 0, 4, 40000, 60, 0, 0 }, + {2800,2801, 0, 4, 40000, 233, 0, 0 }, + {2802,2803, 0, 4, 40000, 80, 0, 0 }, + {2804,2805, 0, 4, 40000, 80, 0, 0 }, + {2806,2807, 0, 4, 4500, 80, 0, 0 }, + {2808,2809, 0, 4, 40000, 73, 0, 0 }, + {2810,2811, 0, 4, 1180, 100, 0, 0 }, + {2812,2813, 0, 4, 953, 153, 0, 0 }, + {2814,2815, 0, 4, 14693, 126, 0, 0 }, + {2816,2817, 0, 4, 14693, 193, 0, 0 }, + {2818,2819, 0, 4, 14473, 633, 0, 0 }, + {2820,2821, 0, 4, 2200, 73, 0, 0 }, + {2822,2823, 0, 4, 366, 86, 0, 0 }, + {2824,2825, 0, 4, 12780, 200, 0, 0 }, + {2826,2827, 0, 4, 40000, 73, 0, 0 }, + {2828,2829, 0, 4, 9066, 146, 0, 0 }, + {2830,2831, 0, 4, 2526, 326, 0, 0 }, + {2832,2833, 0, 4, 6933, 200, 0, 0 }, + {2834,2835, 0, 4, 40000, 413, 0, 0 }, + {2836,2837, 0, 4, 4806, 1313, 0, 0 }, + {2838,2839, 0, 4, 14620, 340, 0, 0 }, + {2840,2841, 0, 4, 1866, 653, 0, 0 }, + {2842,2843, 0, 4, 5200, 260, 0, 0 }, + {2844,2845, 0, 4, 40000, 240, 0, 0 }, + {2846,2847, 0, 4, 40000, 240, 0, 0 }, + {2848,2849, 0, 4, 40000, 240, 0, 0 }, + {2850,2851, 0, 4, 40000, 406, 0, 0 }, + {2852,2853, 0, 4, 40000, 406, 0, 0 }, + {2854,2855, 0, 4, 40000, 146, 0, 0 }, + {2856,2856, 0, 0, 2400, 1126, 0, 0 }, + {2857,2857, 0, 0, 2400, 1126, 0, 0 }, + {2858,2859, 0, 4, 4586, 73, 0, 0 }, + {2860,2861, 0, 4, 40000, 426, 0, 0 }, + {2862,2863, 0, 4, 4553, 100, 0, 0 }, + {2864,2865, 0, 4, 40000, 80, 0, 0 }, + {2866,2867, 0, 4, 5260, 53, 0, 0 }, + {2868,2869, 0, 4, 5286, 113, 0, 0 }, + {2870,2871, 0, 4, 7040, 186, 0, 0 }, + {2872,2873, 0, 4, 4693, 106, 0, 0 }, + {2874,2875, 0, 4, 40000, 73, 0, 0 }, + {2876,2877, 0, 4, 1633, 146, 0, 0 }, + {2878,2879, 0, 4, 7266, 186, 0, 0 }, + {2880,2881, 0, 4, 7340, 1246, 0, 0 }, + {2882,2883, 0, 4, 4600, 93, 0, 0 }, + {2884,2885, 0, 4, 3446, 926, 0, 0 }, + {2886,2887, 0, 4, 40000, 73, 0, 0 }, + {2888,2888, 0, 0, 18926, 426, 0, 0 }, + {2889,2889, 0, 0, 18520, 73, 0, 0 }, + {2890,2890, 0, 0, 18473, 73, 0, 0 }, + {2891,2892, 0, 4, 40000, 93, 0, 0 }, + {2893,2893, 0, 0, 8006, 133, 0, 0 }, + {2894,2894, 0, 0, 18533, 66, 0, 0 }, + {2895,2895, 0, 0, 14786, 4966, 0, 0 }, + {2896,2897, 0, 4, 40000, 80, 0, 0 }, + {2898,2899, 0, 4, 40000, 73, 0, 0 }, + {2353,2900, 0, 4, 18420, 80, 0, 0 }, + {2901,2901, 0, 0, 40000, 0, 0, 0 }, + {2902,2903, 0, 4, 40000, 100, 0, 0 }, + {2904,2905, 0, 4, 40000, 93, 0, 0 }, + {2906,2907, 0, 4, 40000, 73, 0, 0 }, + {2908,2909, 0, 4, 10706, 160, 0, 0 }, + {2910,2911, 0, 4, 40000, 73, 0, 0 }, + {2912,2912, 0, 0, 40000, 40, 0, 0 }, + {2913,2914, 0, 4, 8713, 446, 0, 0 }, + {2915,2916, 0, 4, 14633, 653, 0, 0 }, + {2917,2918, 0, 4, 9166, 426, 0, 0 }, + {2919,2920, 0, 4, 9213, 240, 0, 0 }, + {2921,2922, 0, 4, 8700, 420, 0, 0 }, + {2923,2924, 0, 4, 2200, 346, 0, 0 }, + {2925,2926, 0, 4, 2360, 426, 0, 0 }, + {2927,2928, 0, 4, 2340, 233, 0, 0 }, + {2929,2929, 0, 0, 40000, 140, 0, 0 }, + {2930,2931, 0, 4, 40000, 100, 0, 0 }, + {2932,2933, 0, 4, 40000, 73, 0, 0 }, + {2934,2935, 0, 4, 40000, 80, 0, 0 }, + {2936,2937, 0, 4, 40000, 80, 0, 0 }, + {2938,2939, 0, 4, 40000, 246, 0, 0 }, + {2940,2940, 0, 0, 553, 446, 0, 0 }, + {2941,2941, 0, 0, 40000, 193, 0, 0 }, + {2942,2943, 0, 4, 1200, 406, 0, 0 }, + {2944,2944, 0, 0, 7026, 1553, 0, 0 }, + {2945,2945, 0, 0, 3426, 360, 0, 0 }, + {2946,2947, 0, 4, 7200, 646, 0, 0 }, + {2948,2948, 0, 0, 40000, 386, 0, 0 }, + {2949,2949, 0, 0, 1953, 726, 0, 0 }, + {2950,2951, 0, 4, 14606, 106, 0, 0 }, + {2952,2953, 0, 4, 40000, 1566, 0, 0 }, + {2954,2954, 60, 2, 6, 0, 0, 0 }, + {2955,2956, 0, 4, 40000, 240, 0, 0 }, + {2957,2958, 0, 4, 40000, 80, 0, 0 }, + {2959,2960, 0, 4, 40000, 113, 0, 0 }, + {2961,2962, 0, 4, 40000, 240, 0, 0 }, + {2963,2963, 0, 0, 8506, 680, 0, 0 }, + {2964,2964, 0, 0, 40000, 1593, 0, 0 }, + {2436,2436, 49, 0, 1873, 633, 0, 0 }, + {2357,2357, 61, 0, 113, 20, 0, 0 }, + {2357,2357, 56, 0, 113, 26, 0, 0 }, + {2357,2357, 58, 0, 113, 26, 0, 0 }, + {2357,2357, 49, 0, 126, 26, 0, 0 }, + {2357,2357, 44, 0, 126, 26, 0, 0 }, + {2965,2965, 0, 0, 40000, 380, 0, 0 }, + {2966,2966, 0, 0, 4440, 66, 0, 0 }, + {2967,2967, 0, 0, 8133, 1433, 0, 0 }, + {2968,2968, 0, 0, 40000, 126, 0, 0 }, + {2969,2969, 0, 0, 40000, 0, 0, 0 }, + {2970,2970, 84, 0, 160, 26, 0, 0 }, + {2971,2971, 72, 0, 440, 180, 0, 0 }, + {2972,2972, 0, 0, 8313, 580, 0, 0 }, + {2973,2973, 0, 0, 40000, 160, 0, 0 }, + {2974,2974, 0, 0, 40000, 3000, 0, 0 }, + {2975,2975, 0, 0, 8300, 493, 0, 0 }, + {2976,2976, 0, 0, 973, 673, 0, 0 }, + {2977,2977, 0, 0, 40000, 73, 0, 0 }, + {2978,2978, 0, 0, 40000, 133, 0, 0 }, + {2979,2979, 0, 0, 40000, 140, 0, 0 }, + {2980,2980, 0, 0, 40000, 346, 0, 0 }, + {2981,2981, 0, 0, 40000, 1006, 0, 0 }, + {2982,2982, 0, 0, 40000, 966, 0, 0 }, + {2983,2983, 0, 0, 40000, 0, 0, 0 }, + {2984,2984, 0, 0, 40000, 0, 0, 0 }, + {2985,2985, 0, 0, 40000, 66, 0, 0 }, + {2986,2986, 0, 0, 40000, 66, 0, 0 }, + {2987,2987, 0, 0, 40000, 46, 0, 0 }, + {2988,2988, 0, 0, 40000, 533, 0, 0 }, + {2989,2989, 0, 0, 2400, 780, 0, 0 }, + {2990,2990, 0, 0, 820, 66, 0, 0 }, + {2991,2991, 0, 0, 40000, 240, 0, 0 }, + {2992,2992, 0, 0, 40000, 220, 0, 0 }, + {2993,2993, 0, 0, 40000, 0, 0, 0 }, + {2994,2994, 0, 0, 15100, 73, 0, 0 }, + {2995,2995, 0, 0, 40000, 200, 0, 0 }, + {2996,2996, 0, 0, 2426, 93, 0, 0 }, + {2997,2997, 0, 0, 4640, 1553, 0, 0 }, + {2998,2998, 0, 0, 40000, 73, 0, 0 }, + {2999,2999, 0, 0, 40000, 73, 0, 0 }, + {3000,3000, 0, 0, 1133, 633, 0, 0 }, + {3001,3001, 0, 0, 40000, 0, 0, 0 }, + {3002,3002, 0, 0, 40000, 1006, 0, 0 }, + {3003,3003, 0, 0, 4653, 653, 0, 0 }, + {3004,3004, 0, 0, 40000, 1000, 0, 0 }, + {3005,3005, 0, 0, 40000, 53, 0, 0 }, + {3006,3006, 0, 0, 40000, 60, 0, 0 }, + {3007,3007, 0, 0, 40000, 0, 0, 0 }, + { 350, 350, 0, 0, 513, 200, 0, 0 }, + {3008,3008, 0, 0, 213, 106, 0, 0 }, + {3009,3009, 0, 0, 280, 126, 0, 0 }, + {3010,3010, 0, 0, 1193, 426, 0, 0 }, + {3011,3011, 0, 0, 14653, 4906, 0, 0 }, + {3012,3012, 0, 0, 1040, 326, 0, 0 }, + {3013,3013, 0, 0, 5740, 2326, 0, 0 }, + {3014,3014, 0, 0, 40000, 73, 0, 0 }, + {3015,3015, 0, 0, 40000, 240, 0, 0 }, + { 350, 350, 36, 0, 380, 153, 0, 0 }, + { 369, 369, 37, 0, 213, 66, 0, 0 }, + {3008,3008, 38, 0, 213, 106, 0, 0 }, + { 369, 369, 24, 0, 193, 13, 0, 0 }, + {3008,3008, 32, 0, 206, 106, 0, 0 }, + { 369, 369, 48, 0, 186, 20, 0, 0 }, + {3009,3009, 42, 0, 220, 106, 0, 0 }, + { 369, 369, 50, 0, 186, 73, 0, 0 }, + { 369, 369, 52, 0, 186, 73, 0, 0 }, + { 369, 369, 54, 0, 186, 33, 0, 0 }, + { 369, 369, 55, 0, 186, 33, 0, 0 }, + { 369, 369, 57, 0, 180, 33, 0, 0 }, + {3010,3010, 51, 0, 966, 353, 0, 0 }, + { 144, 144, 61, 0, 213, 126, 0, 0 }, + {3016,3016, 0, 0, 8340, 520, 0, 0 }, + {3016,3016, 63, 0, 6106, 373, 0, 0 }, + {3016,3016, 64, 0, 6073, 380, 0, 0 }, + {3017,3017, 40, 0, 206, 100, 0, 0 }, + {3017,3017, 70, 0, 160, 93, 0, 0 }, + {3018,3018, 0, 0, 40000, 73, 0, 0 }, + {3019,3019, 0, 0, 40000, 73, 0, 0 }, + {3020,3020, 0, 0, 40000, 73, 0, 0 }, + {3021,3021, 0, 0, 40000, 73, 0, 0 }, + {3022,3022, 38, 0, 246, 33, 0, 0 }, + {2441,2441, 57, 0, 286, 126, 0, 0 }, + {3023,3023, 63, 0, 146, 126, 0, 0 }, + {3024,3024, 74, 0, 280, 73, 0, 0 }, + {3025,3025, 74, 0, 453, 100, 0, 0 }, + {3026,3026, 60, 0, 666, 33, 0, 0 }, + {1593,1594, 35, 4, 1220, 413, 0, 0 }, + {1564,1565, 35, 4, 700, 260, 0, 0 }, + { 248,3027, 0, 4, 40000, 126, 0, 0 }, + {1445,3028, 0, 4, 9920, 326, 0, 0 }, + {1447,3029, 0, 4, 10133, 26, 0, 0 }, + {1452,3030, 0, 4, 9213, 240, 0, 0 }, + {1544,3031, 0, 4, 293, 86, 0, 0 }, + {1546,3032, 0, 4, 40000, 153, 0, 0 }, + { 398, 399, 35, 4, 1906, 226, 0, 0 }, + {1550,3033, 35, 4, 66, 26, 0, 0 }, + {1556,1557, 35, 4, 1126, 426, 0, 0 }, + {1558,1559, 35, 4, 1126, 413, 0, 0 }, + {1570,1571, 35, 4, 493, 100, 0, 0 }, + {1608,1609, 35, 4, 2286, 413, 0, 0 }, + {1595,1596, 35, 4, 220, 260, 0, 0 }, + { 159,1597, 35, 4, 220, 273, 0, 0 }, + {1610,1611, 35, 4, 220, 260, 0, 0 }, + { 397,1588, 35, 4, 253, 86, 0, 0 }, + {1606,1607, 35, 4, 140, 60, 0, 0 }, + { 145,1576, 35, 4, 160, 120, 0, 0 }, + {1612,1613, 35, 4, 413, 440, 0, 0 }, + {1577,1578, 35, 4, 373, 393, 0, 0 }, + {1614,1615, 35, 4, 706, 760, 0, 0 }, + {1550,1551, 35, 4, 620, 240, 0, 0 }, + { 364, 365, 35, 4, 146, 26, 0, 0 }, + { 129,1549, 35, 4, 200, 100, 0, 0 }, + { 132,1552, 35, 4, 213, 106, 0, 0 }, + {1553,1554, 35, 4, 206, 73, 0, 0 }, + { 129,1548, 35, 4, 200, 100, 0, 0 }, + { 134,1555, 35, 4, 2233, 680, 0, 0 }, + {1560,1561, 35, 4, 353, 146, 0, 0 }, + {1562,1563, 35, 4, 2013, 426, 0, 0 }, + {1572,1573, 35, 4, 346, 153, 0, 0 }, + {1574,1575, 35, 4, 360, 246, 0, 0 }, + {1581,1582, 35, 4, 620, 246, 0, 0 }, + { 149,1583, 35, 4, 326, 33, 0, 0 }, + {1584,1585, 35, 4, 200, 100, 0, 0 }, + {1591,1592, 35, 4, 1206, 413, 0, 0 }, + {1579,1580, 35, 4, 273, 233, 0, 0 }, + {1586,1587, 35, 4, 200, 100, 0, 0 }, + {1589,1590, 35, 4, 120, 86, 0, 0 }, + {1600,1601, 35, 4, 1246, 373, 0, 0 }, + {1602,1603, 35, 4, 700, 273, 0, 0 }, + {1604,1605, 35, 4, 2660, 926, 0, 0 }, + {1598,1599, 35, 4, 1300, 400, 0, 0 }, + { 374, 375, 35, 4, 1186, 426, 0, 0 }, + {1566,1567, 35, 4, 2333, 813, 0, 0 }, + {2306,2307, 35, 4, 2360, 906, 0, 0 }, + {3034, 339, 35, 6, 6, 0, 0, 0 }, + {2305,1548, 35, 4, 200, 100, 0, 0 }, + {1595,1595, 35, 0, 220, 273, 0, 0 }, + {2303,2304, 35, 4, 146, 26, 0, 0 }, + {1560,2308, 35, 4, 353, 233, 0, 0 }, + {2309,2310, 35, 4, 2013, 433, 0, 0 }, + {1568,1568, 35, 0, 1280, 453, 0, 0 }, + {2311,2312, 35, 4, 346, 146, 0, 0 }, + {2313,2314, 35, 4, 633, 240, 0, 0 }, + {2315,2315, 35, 0, 106, 46, 0, 0 }, + {2316,2316, 35, 0, 506, 453, 0, 0 }, + {1612,1612, 35, 0, 526, 400, 0, 0 }, + {2317,2317, 35, 0, 640, 253, 0, 0 }, + {2318,2318, 35, 0, 326, 20, 0, 0 }, + {2319,2319, 35, 0, 453, 446, 0, 0 }, + {2320,2320, 35, 0, 466, 453, 0, 0 }, + {2321,2321, 35, 0, 120, 26, 0, 0 }, + {2322,2322, 35, 0, 1220, 406, 0, 0 }, + {2323,2323, 35, 0, 2360, 786, 0, 0 }, + {2324, 392, 35, 4, 180, 46, 0, 0 }, + {2324, 393, 35, 4, 460, 66, 0, 0 }, + {2325,2326, 35, 4, 533, 133, 0, 0 }, + {2327,2328, 35, 4, 1273, 406, 0, 0 }, + {2329,2330, 35, 4, 613, 773, 0, 0 }, + {2331,2332, 35, 4, 2340, 780, 0, 0 }, + {3035,3036, 35, 4, 1193, 433, 0, 0 }, + {3037,3038, 35, 4, 1840, 340, 0, 0 }, + {1564,1564, 35, 0, 713, 273, 0, 0 }, + {3039,3039, 0, 0, 40000, 0, 0, 0 }, + {3040,3040, 0, 0, 6100, 146, 0, 0 }, + {3041,3041, 0, 0, 2386, 26, 0, 0 }, + {3042,3042, 0, 0, 4320, 80, 0, 0 }, + {3043,3043, 0, 0, 3433, 313, 0, 0 }, + {3044,3044, 0, 0, 6620, 2446, 0, 0 }, + {3045,3045, 0, 0, 3726, 1253, 0, 0 }, + {3046,3046, 0, 0, 40000, 133, 0, 0 }, + {3047,3047, 0, 0, 4566, 1253, 0, 0 }, + {3048,3048, 0, 0, 40000, 813, 0, 0 }, + {3049,3049, 0, 0, 18513, 1560, 0, 0 }, + {3050,3050, 0, 0, 2186, 426, 0, 0 }, + {3051,3051, 0, 0, 1186, 420, 0, 0 }, + {3052,3052, 0, 0, 766, 420, 0, 0 }, + {3053,3053, 0, 0, 14513, 4713, 0, 0 }, + {3054,3054, 0, 0, 15493, 1580, 0, 0 }, + {3055,3055, 0, 0, 40000, 66, 0, 0 }, + {3056,3056, 0, 0, 40000, 60, 0, 0 }, + {3057,3057, 0, 0, 4740, 100, 0, 0 }, + {3058,3058, 0, 0, 40000, 66, 0, 0 }, + {3059,3059, 0, 0, 40000, 73, 0, 0 }, + {3060,3060, 0, 0, 40000, 73, 0, 0 }, + {3061,3061, 0, 0, 40000, 0, 0, 0 }, + {3062,3062, 0, 0, 8373, 633, 0, 0 }, + {3063,3063, 0, 0, 7560, 133, 0, 0 }, + {3064,3064, 0, 0, 40000, 0, 0, 0 }, + {3065,3065, 0, 0, 40000, 86, 0, 0 }, + {3066,3066, 0, 0, 340, 140, 0, 0 }, + {3067,3067, 0, 0, 40000, 0, 0, 0 }, + {3068,3068, 0, 0, 40000, 166, 0, 0 }, + {3069,3069, 0, 0, 4280, 1466, 0, 0 }, + {3070,3070, 0, 0, 2193, 73, 0, 0 }, + {3071,3071, 0, 0, 4846, 100, 0, 0 }, + {3072,3072, 0, 0, 12740, 93, 0, 0 }, + {3073,3073, 0, 0, 6953, 200, 0, 0 }, + {3074,3074, 0, 0, 13780, 73, 0, 0 }, + {3075,3075, 0, 0, 40000, 73, 0, 0 }, + {3076,3076, 0, 0, 5860, 600, 0, 0 }, + {3077,3077, 0, 0, 2206, 73, 0, 0 }, + {3078,3078, 0, 0, 40000, 140, 0, 0 }, + {3079,3079, 0, 0, 40000, 53, 0, 0 }, + {3080,3080, 0, 0, 40000, 120, 0, 0 }, + {3081,3081, 0, 0, 40000, 140, 0, 0 }, + {3082,3082, 0, 0, 40000, 126, 0, 0 }, + {3083,3083, 0, 0, 360, 140, 0, 0 }, + {3084,3084, 0, 0, 8880, 1373, 0, 0 }, + {3085,3085, 0, 0, 593, 73, 0, 0 }, + {3086,3086, 0, 0, 40000, 193, 0, 0 }, + {3087,3087, 0, 0, 40000, 200, 0, 0 }, + {3088,3088, 0, 0, 40000, 160, 0, 0 }, + {3089,3089, 0, 0, 40000, 200, 0, 0 }, + {3090,3090, 0, 0, 40000, 53, 0, 0 }, + {3091,3091, 0, 0, 40000, 73, 0, 0 }, + {3092,3092, 0, 0, 40000, 73, 0, 0 }, + {3093,3093, 0, 0, 760, 213, 0, 0 }, + {3094,3094, 0, 0, 40000, 133, 0, 0 }, + {3095,3095, 0, 0, 40000, 220, 0, 0 }, + {3096,3096, 0, 0, 40000, 100, 0, 0 }, + {3097,3097, 0, 0, 40000, 73, 0, 0 }, + {3098,3098, 0, 0, 40000, 140, 0, 0 }, + {3099,3099, 0, 0, 40000, 140, 0, 0 }, + {3100,3100, 0, 0, 40000, 140, 0, 0 }, + {3101,3101, 0, 0, 40000, 73, 0, 0 }, + {3102,3102, 0, 0, 40000, 73, 0, 0 }, + {3103,3103, 0, 0, 40000, 73, 0, 0 }, + {3104,3104, 0, 0, 40000, 73, 0, 0 }, + {3105,3105, 0, 0, 40000, 66, 0, 0 }, + {3106,3106, 0, 0, 40000, 66, 0, 0 }, + {3107,3107, 0, 0, 40000, 73, 0, 0 }, + {3108,3108, 0, 0, 40000, 73, 0, 0 }, + {3109,3109, 0, 0, 40000, 73, 0, 0 }, + {3110,3110, 0, 0, 40000, 73, 0, 0 }, + {3111,3111, 0, 0, 40000, 86, 0, 0 }, + {3112,3112, 0, 0, 5393, 100, 0, 0 }, + {3113,3113, 0, 0, 40000, 60, 0, 0 }, + {3114,3114, 0, 0, 18500, 73, 0, 0 }, + {3115,3115, 0, 0, 40000, 93, 0, 0 }, + {3116,3116, 0, 0, 40000, 86, 0, 0 }, + {3117,3117, 0, 0, 40000, 173, 0, 0 }, + {3118,3118, 0, 0, 40000, 1353, 0, 0 }, + {3119,3119, 0, 0, 17506, 73, 0, 0 }, + {3120,3120, 0, 0, 40000, 100, 0, 0 }, + {3121,3121, 0, 0, 40000, 73, 0, 0 }, + {3122,3122, 0, 0, 5620, 193, 0, 0 }, + {3123,3123, 0, 0, 3700, 80, 0, 0 }, + {3124,3124, 0, 0, 40000, 66, 0, 0 }, + {3125,3125, 0, 0, 2740, 80, 0, 0 }, + {3126,3126, 0, 0, 8333, 173, 0, 0 }, + {3127,3127, 0, 0, 2226, 466, 0, 0 }, + {3128,3128, 0, 0, 340, 146, 0, 0 }, + {3129,3129, 0, 0, 19980, 6280, 0, 0 }, + {3130,3130, 0, 0, 353, 73, 0, 0 }, + {3131,3131, 35, 0, 566, 233, 0, 0 }, + {3132,3132, 35, 0, 226, 46, 0, 0 }, + {3133,3133, 35, 0, 40000, 100, 0, 0 }, + {3134,3134, 35, 0, 40000, 100, 0, 0 }, + {3135,3135, 35, 0, 360, 146, 0, 0 }, + {3061,3061, 35, 0, 40000, 0, 0, 0 }, + {3136,3136, 35, 0, 366, 20, 0, 0 }, + { 739, 739, 35, 0, 246, 20, 0, 0 }, + {3137,3137, 35, 0, 333, 33, 0, 0 }, + {3138,3138, 35, 0, 420, 166, 0, 0 }, + {3139,3139, 35, 0, 626, 240, 0, 0 }, + {3140,3140, 35, 0, 233, 100, 0, 0 }, + {3141,3141, 35, 0, 1166, 440, 0, 0 }, + {3142,3142, 35, 0, 166, 66, 0, 0 }, + {3143,3143, 35, 0, 1166, 440, 0, 0 }, + {3144,3144, 35, 0, 813, 100, 0, 0 }, + {3145,3145, 35, 0, 1040, 440, 0, 0 }, + {3146,3146, 35, 0, 40000, 0, 0, 0 }, + {3147,3147, 35, 0, 40000, 0, 0, 0 }, + {3148,3148, 35, 0, 180, 40, 0, 0 }, + {3149,3149, 35, 0, 40000, 0, 0, 0 }, + {3150,3150, 0, 0, 40000, 0, 0, 0 }, + {3151,3151, 0, 0, 4900, 240, 0, 0 }, + {3152,3152, 0, 0, 3480, 80, 0, 0 }, + {3153,3153, 0, 0, 3586, 86, 0, 0 }, + {3154,3154, 0, 0, 4626, 633, 0, 0 }, + {3155,3155, 0, 0, 4293, 2286, 0, 0 }, + {3156,3156, 0, 0, 13653, 4720, 0, 0 }, + {3157,3157, 0, 0, 1206, 426, 0, 0 }, + {3158,3158, 0, 0, 653, 426, 0, 0 }, + {3159,3159, 0, 0, 40000, 0, 0, 0 }, + {3160,3160, 0, 0, 4633, 633, 0, 0 }, + {3161,3161, 0, 0, 40000, 73, 0, 0 }, + {3162,3162, 0, 0, 40000, 60, 0, 0 }, + {3163,3163, 0, 0, 40000, 146, 0, 0 }, + {3164,3164, 0, 0, 40000, 73, 0, 0 }, + {3165,3165, 0, 0, 40000, 73, 0, 0 }, + {3166,3166, 0, 0, 40000, 0, 0, 0 }, + {3167,3167, 0, 0, 40000, 66, 0, 0 }, + {3168,3168, 0, 0, 3680, 1180, 0, 0 }, + {3169,3169, 0, 0, 2406, 846, 0, 0 }, + {3170,3170, 0, 0, 1560, 73, 0, 0 }, + {3171,3171, 0, 0, 1946, 226, 0, 0 }, + {3172,3172, 0, 0, 4333, 13, 0, 0 }, + {3173,3173, 0, 0, 40000, 0, 0, 0 }, + {3174,3174, 0, 0, 40000, 0, 0, 0 }, + {3175,3175, 0, 0, 40000, 66, 0, 0 }, + {3176,3176, 0, 0, 40000, 180, 0, 0 }, + {3177,3177, 0, 0, 15380, 80, 0, 0 }, + {3178,3178, 0, 0, 18213, 73, 0, 0 }, + {3179,3179, 0, 0, 1706, 0, 0, 0 }, + {3180,3180, 0, 0, 5733, 1266, 0, 0 }, + {3181,3181, 0, 0, 40000, 0, 0, 0 }, + {3182,3182, 0, 0, 40000, 366, 0, 0 }, + {3183,3183, 0, 0, 40000, 66, 0, 0 }, + {3184,3184, 0, 0, 4786, 73, 0, 0 }, + {3185,3185, 0, 0, 5660, 720, 0, 0 }, + {3186,3186, 0, 0, 1293, 406, 0, 0 }, + {3187,3187, 0, 0, 40000, 0, 0, 0 }, + {3188,3188, 0, 0, 2686, 233, 0, 0 }, + {3189,3189, 0, 0, 40000, 0, 0, 0 }, + {3190,3190, 0, 0, 40000, 73, 0, 0 }, + {3191,3191, 0, 0, 40000, 0, 0, 0 }, + {3192,3192, 0, 0, 40000, 73, 0, 0 }, + {3193,3193, 0, 0, 40000, 0, 0, 0 }, + {3194,3194, 0, 0, 3920, 73, 0, 0 }, + {3195,3195, 0, 0, 40000, 73, 0, 0 }, + {3196,3196, 0, 0, 40000, 66, 0, 0 }, + {3197,3197, 0, 0, 40000, 80, 0, 0 }, + {3198,3198, 0, 0, 40000, 86, 0, 0 }, + {3199,3199, 0, 0, 40000, 60, 0, 0 }, + {3200,3200, 0, 0, 40000, 0, 0, 0 }, + {3201,3201, 0, 0, 40000, 353, 0, 0 }, + {3202,3202, 0, 0, 3920, 73, 0, 0 }, + {3203,3203, 0, 0, 5833, 813, 0, 0 }, + {3204,3204, 0, 0, 40000, 60, 0, 0 }, + {3205,3205, 0, 0, 40000, 73, 0, 0 }, + {3206,3206, 0, 0, 1400, 406, 0, 0 }, + {3207,3207, 0, 0, 40000, 66, 0, 0 }, + {3208,3208, 0, 0, 9066, 2220, 0, 0 }, + {3209,3209, 0, 0, 1473, 773, 0, 0 }, + {3210,3210, 0, 0, 40000, 120, 0, 0 }, + {3211,3211, 0, 0, 40000, 306, 0, 0 }, + {3212,3212, 0, 0, 9306, 3013, 0, 0 }, + {3213,3213, 0, 0, 40000, 60, 0, 0 }, + {3214,3214, 0, 0, 40000, 73, 0, 0 }, + {3215,3215, 0, 0, 40000, 73, 0, 0 }, + {3216,3216, 0, 0, 40000, 453, 0, 0 }, + {3217,3217, 0, 0, 40000, 3460, 0, 0 }, + {3218,3218, 0, 0, 40000, 453, 0, 0 }, + {3219,3219, 0, 0, 40000, 40, 0, 0 }, + {3220,3220, 0, 0, 40000, 3926, 0, 0 }, + {3221,3221, 0, 0, 40000, 4506, 0, 0 }, + {3222,3222, 0, 0, 4646, 646, 0, 0 }, + {3223,3223, 0, 0, 773, 100, 0, 0 }, + {3224,3224, 0, 0, 40000, 73, 0, 0 }, + {3225,3225, 0, 0, 40000, 173, 0, 0 }, + {3226,3226, 0, 0, 1606, 653, 0, 0 }, + {3227,3227, 0, 0, 2353, 806, 0, 0 }, + {3228,3228, 0, 0, 980, 360, 0, 0 }, + {3229,3229, 0, 0, 1193, 413, 0, 0 }, + { 499, 499, 0, 0, 266, 160, 0, 0 }, + {3230,3230, 0, 0, 973, 360, 0, 0 }, + {3231,3231, 0, 0, 273, 53, 0, 0 }, + {3232,3232, 0, 0, 726, 220, 0, 0 }, + {3233,3233, 0, 0, 19933, 6093, 0, 0 }, + {3234,3234, 0, 0, 40000, 0, 0, 0 }, + { 403, 403, 0, 0, 40000, 73, 0, 0 }, + {3235,3235, 0, 0, 4966, 233, 0, 0 }, + {3236,3236, 0, 0, 4946, 240, 0, 0 }, + {3237,3237, 0, 0, 4946, 233, 0, 0 }, + {3238,3238, 0, 0, 4640, 1613, 0, 0 }, + {3239,3239, 0, 0, 2360, 806, 0, 0 }, + {3240,3240, 0, 0, 4466, 200, 0, 0 }, + {3241,3241, 0, 0, 40000, 73, 0, 0 }, + {3242,3242, 0, 0, 40000, 73, 0, 0 }, + {3243,3243, 0, 0, 40000, 73, 0, 0 }, + {3244,3244, 0, 0, 40000, 73, 0, 0 }, + {3245,3245, 0, 0, 40000, 240, 0, 0 }, + {3246,3246, 0, 0, 40000, 226, 0, 0 }, + {3247,3247, 0, 0, 40000, 233, 0, 0 }, + {3248,3248, 0, 0, 40000, 240, 0, 0 }, + {3249,3249, 0, 0, 4306, 1253, 0, 0 }, + {3250,3250, 0, 0, 3873, 1206, 0, 0 }, + {3251,3251, 0, 0, 4640, 633, 0, 0 }, + {3252,3252, 0, 0, 1233, 80, 0, 0 }, + {3253,3253, 0, 0, 1233, 26, 0, 0 }, + {3254,3254, 0, 0, 1233, 26, 0, 0 }, + {3255,3255, 0, 0, 4573, 1253, 0, 0 }, + {3256,3256, 0, 0, 3793, 1240, 0, 0 }, + {3257,3257, 0, 0, 40000, 73, 0, 0 }, + {3258,3258, 0, 0, 40000, 73, 0, 0 }, + {3259,3259, 0, 0, 40000, 140, 0, 0 }, + {3260,3260, 0, 0, 40000, 146, 0, 0 }, + {3261,3261, 0, 0, 40000, 80, 0, 0 }, + {3262,3262, 0, 0, 5953, 200, 0, 0 }, + {3263,3263, 0, 0, 5926, 200, 0, 0 }, + {3264,3264, 0, 0, 5866, 26, 0, 0 }, + {3265,3265, 0, 0, 18573, 6153, 0, 0 }, + {3266,3266, 0, 0, 40000, 2093, 0, 0 }, + {3267,3267, 0, 0, 40000, 73, 0, 0 }, + {3268,3268, 0, 0, 18626, 1553, 0, 0 }, + {3269,3269, 0, 0, 40000, 1820, 0, 0 }, + {3270,3270, 0, 0, 40000, 500, 0, 0 }, + {3271,3271, 0, 0, 18206, 5900, 0, 0 }, + {3272,3272, 0, 0, 14200, 93, 0, 0 }, + {3273,3273, 0, 0, 40000, 2873, 0, 0 }, + {3274,3274, 0, 0, 14960, 4913, 0, 0 }, + {3275,3275, 0, 0, 40000, 86, 0, 0 }, + {3276,3276, 0, 0, 40000, 826, 0, 0 }, + {3277,3277, 0, 0, 40000, 200, 0, 0 }, + {3278,3278, 0, 0, 40000, 340, 0, 0 }, + {3279,3279, 0, 0, 13220, 2500, 0, 0 }, + {3280,3280, 0, 0, 40000, 100, 0, 0 }, + {3281,3281, 0, 0, 40000, 1026, 0, 0 }, + {3282,3282, 0, 0, 40000, 366, 0, 0 }, + {3283,3283, 0, 0, 40000, 386, 0, 0 }, + {3284,3284, 0, 0, 40000, 0, 0, 0 }, + {3285,3285, 0, 0, 40000, 0, 0, 0 }, + {3286,3286, 0, 0, 40000, 140, 0, 0 }, + {3287,3287, 0, 0, 40000, 53, 0, 0 }, + {3288,3288, 0, 0, 40000, 120, 0, 0 }, + {3289,3289, 0, 0, 8866, 1366, 0, 0 }, + {3290,3290, 0, 0, 4193, 1400, 0, 0 }, + {3291,3291, 0, 0, 8353, 673, 0, 0 }, + {3292,3292, 0, 0, 8353, 673, 0, 0 }, + {3293,3293, 0, 0, 8400, 593, 0, 0 }, + {3294,3294, 0, 0, 8440, 666, 0, 0 }, + {3295,3295, 0, 0, 9600, 1580, 0, 0 }, + {3296,3296, 0, 0, 40000, 46, 0, 0 }, + {3297,3297, 0, 0, 40000, 0, 0, 0 }, + {3298,3298, 0, 0, 1653, 93, 0, 0 }, + {3299,3299, 0, 0, 2706, 73, 0, 0 }, + {3300,3300, 0, 0, 11680, 26, 0, 0 }, + {3301,3301, 0, 0, 6500, 340, 0, 0 }, + {3302,3302, 0, 0, 40000, 0, 0, 0 }, + {3303,3303, 0, 0, 40000, 0, 0, 0 }, + {3304,3304, 0, 0, 40000, 73, 0, 0 }, + {3305,3305, 0, 0, 40000, 73, 0, 0 }, + {3306,3306, 0, 0, 40000, 73, 0, 0 }, + {3307,3307, 0, 0, 40000, 73, 0, 0 }, + {3308,3308, 0, 0, 40000, 73, 0, 0 }, + {3309,3309, 0, 0, 40000, 73, 0, 0 }, + {3310,3310, 0, 0, 40000, 73, 0, 0 }, + {3311,3311, 0, 0, 40000, 73, 0, 0 }, + {3312,3312, 0, 0, 40000, 73, 0, 0 }, + {3313,3313, 0, 0, 40000, 133, 0, 0 }, + {3314,3314, 0, 0, 40000, 126, 0, 0 }, + {3315,3315, 0, 0, 40000, 73, 0, 0 }, + {3316,3316, 0, 0, 40000, 73, 0, 0 }, + {3317,3317, 0, 0, 40000, 73, 0, 0 }, + {3318,3318, 0, 0, 40000, 200, 0, 0 }, + {3319,3319, 0, 0, 40000, 133, 0, 0 }, + {3320,3320, 0, 0, 40000, 0, 0, 0 }, + {3321,3321, 0, 0, 40000, 240, 0, 0 }, + {3322,3322, 0, 0, 40000, 220, 0, 0 }, + {3323,3323, 0, 0, 40000, 226, 0, 0 }, + {3324,3324, 0, 0, 40000, 100, 0, 0 }, + {3325,3325, 0, 0, 40000, 140, 0, 0 }, + {3326,3326, 0, 0, 40000, 0, 0, 0 }, + {3327,3327, 0, 0, 40000, 426, 0, 0 }, + {3328,3328, 0, 0, 40000, 426, 0, 0 }, + {3329,3329, 0, 0, 3680, 1220, 0, 0 }, + {3330,3330, 0, 0, 40000, 533, 0, 0 }, + {3331,3331, 0, 0, 40000, 813, 0, 0 }, + {3332,3332, 0, 0, 14506, 4706, 0, 0 }, + {3333,3333, 0, 0, 766, 420, 0, 0 }, + {3334,3334, 0, 0, 40000, 1566, 0, 0 }, + {3335,3335, 0, 0, 40000, 120, 0, 0 }, + {3336,3336, 0, 0, 40000, 2380, 0, 0 }, + {3337,3337, 0, 0, 5666, 300, 0, 0 }, + {3338,3338, 0, 0, 40000, 73, 0, 0 }, + {3339,3339, 0, 0, 40000, 2513, 0, 0 }, + {3340,3340, 0, 0, 1260, 826, 0, 0 }, + {3341,3341, 0, 0, 2420, 413, 0, 0 }, + {3342,3342, 0, 0, 626, 240, 0, 0 }, + {3343,3343, 0, 0, 273, 60, 0, 0 }, + {3344,3344, 0, 0, 540, 20, 0, 0 }, + {3345,3345, 0, 0, 540, 20, 0, 0 }, + {3346,3346, 0, 0, 540, 20, 0, 0 }, + {3347,3347, 0, 0, 1153, 760, 0, 0 }, + {3348,3348, 0, 0, 40000, 100, 0, 0 }, + {3349,3349, 0, 0, 7326, 2380, 0, 0 }, + {3350,3350, 0, 0, 40000, 4426, 0, 0 }, + {3351,3351, 0, 0, 7413, 2493, 0, 0 }, + {3352,3352, 0, 0, 253, 20, 0, 0 }, + {3353,3353, 0, 0, 246, 33, 0, 0 }, + {3354,3354, 0, 0, 286, 13, 0, 0 }, + {3355,3355, 0, 0, 953, 13, 0, 0 }, + {3356,3356, 0, 0, 293, 20, 0, 0 }, + { 142, 142, 20, 0, 1893, 620, 0, 0 }, + {3357,1451, 0, 4, 2340, 780, 0, 0 }, + {3358,3359, 0, 4, 9206, 240, 0, 0 }, + {3360,1455, 0, 4, 40000, 0, 0, 0 }, + {3361,1463, 0, 4, 40000, 266, 0, 0 }, + { 225,3362, 0, 4, 7993, 100, 0, 0 }, + {3363,1545, 0, 4, 293, 86, 0, 0 }, + {3364,1547, 0, 4, 40000, 180, 0, 0 }, + {3365,3366, 39, 4, 66, 26, 0, 0 }, + {3367, 368, 58, 4, 173, 93, 0, 0 }, + {3368,1551, 48, 4, 520, 200, 0, 0 }, + {3368,3033, 49, 4, 53, 26, 0, 0 }, + {3368,3033, 51, 4, 53, 26, 0, 0 }, + {3368,3033, 54, 4, 60, 26, 0, 0 }, + {3368,3033, 57, 4, 60, 26, 0, 0 }, + {3368,3033, 60, 4, 60, 26, 0, 0 }, + {3369,3370, 70, 4, 773, 306, 0, 0 }, + {1564,1565, 80, 4, 220, 106, 0, 0 }, + {3371,1571, 44, 4, 413, 93, 0, 0 }, + {3372,3372, 0, 0, 8366, 666, 0, 0 }, + {3373,3373, 0, 0, 8366, 666, 0, 0 }, + {3374,3374, 0, 0, 3773, 73, 0, 0 }, + {3375,3375, 0, 0, 8366, 666, 0, 0 }, + {3376,3376, 0, 0, 4693, 26, 0, 0 }, + {3377,3377, 0, 0, 7400, 80, 0, 0 }, + {3378,3378, 0, 0, 3586, 80, 0, 0 }, + {3379,3379, 0, 0, 8366, 666, 0, 0 }, + {3380,3380, 0, 0, 3786, 1240, 0, 0 }, + {3381,3381, 0, 0, 9013, 1466, 0, 0 }, + {3382,3382, 0, 0, 1200, 73, 0, 0 }, + {3383,3383, 0, 0, 8146, 1446, 0, 0 }, + {3384,3384, 0, 0, 3660, 1206, 0, 0 }, + {3385,3385, 0, 0, 200, 100, 0, 0 }, + {3386,3386, 0, 0, 40000, 0, 0, 0 }, + {3387,3387, 0, 0, 1213, 426, 0, 0 }, + {3388,3388, 0, 0, 40000, 2573, 0, 0 }, + {3389,3389, 0, 0, 40000, 3446, 0, 0 }, + {3390,3390, 0, 0, 40000, 333, 0, 0 }, + {3391,3391, 0, 0, 40000, 73, 0, 0 }, + {3392,3392, 0, 0, 40000, 93, 0, 0 }, + {3393,3393, 0, 0, 40000, 73, 0, 0 }, + {3394,3394, 0, 0, 40000, 73, 0, 0 }, + {3395,3395, 0, 0, 40000, 73, 0, 0 }, + {3396,3396, 0, 0, 2193, 413, 0, 0 }, + {3397,3397, 0, 0, 14606, 2886, 0, 0 }, + {3398,3398, 0, 0, 10626, 4520, 0, 0 }, + {3399,3399, 0, 0, 2413, 100, 0, 0 }, + {3400,3400, 0, 0, 3593, 1140, 0, 0 }, + {3401,3401, 0, 0, 40000, 146, 0, 0 }, + {3402,3402, 0, 0, 40000, 86, 0, 0 }, + {3403,3403, 0, 0, 40000, 86, 0, 0 }, + {3404,3404, 0, 0, 9366, 106, 0, 0 }, + {3405,3405, 0, 0, 40000, 73, 0, 0 }, + {3406,3406, 0, 0, 40000, 0, 0, 0 }, + {3407,3407, 0, 0, 40000, 0, 0, 0 }, + {3408,3408, 0, 0, 1626, 400, 0, 0 }, + {3409,3409, 0, 0, 4473, 2933, 0, 0 }, + {3410,3410, 0, 0, 40000, 66, 0, 0 }, + {3411,3411, 0, 0, 40000, 0, 0, 0 }, + {3412,3412, 0, 0, 40000, 253, 0, 0 }, + {3413,3413, 0, 0, 40000, 233, 0, 0 }, + {3414,3414, 0, 0, 40000, 346, 0, 0 }, + {3415,3415, 0, 0, 1966, 26, 0, 0 }, + {3416,3416, 0, 0, 40000, 366, 0, 0 }, + {3417,3417, 0, 0, 2266, 386, 0, 0 }, + {3418,3418, 0, 0, 40000, 0, 0, 0 }, + {3419,3419, 0, 0, 2313, 766, 0, 0 }, + {3420,3420, 0, 0, 40000, 340, 0, 0 }, + {3421,3421, 0, 0, 40000, 346, 0, 0 }, + {3422,3422, 0, 0, 40000, 340, 0, 0 }, + {3423,3423, 0, 0, 40000, 353, 0, 0 }, + {3424,3424, 0, 0, 40000, 353, 0, 0 }, + {3425,3425, 0, 0, 40000, 226, 0, 0 }, + {3426,3426, 0, 0, 40000, 73, 0, 0 }, + {3427,3427, 0, 0, 940, 253, 0, 0 }, + {3428,3428, 0, 0, 40000, 73, 0, 0 }, + {3429,3429, 0, 0, 40000, 80, 0, 0 }, + {3430,3430, 0, 0, 40000, 240, 0, 0 }, + {3431,3431, 0, 0, 40000, 80, 0, 0 }, + {3432,3432, 0, 0, 40000, 73, 0, 0 }, + {3433,3433, 0, 0, 40000, 73, 0, 0 }, + {3434,3434, 0, 0, 40000, 73, 0, 0 }, + {3435,3435, 0, 0, 40000, 73, 0, 0 }, + {3436,3436, 0, 0, 40000, 73, 0, 0 }, + {3437,3437, 0, 0, 40000, 73, 0, 0 }, + {3438,3438, 0, 0, 40000, 73, 0, 0 }, + {3439,3439, 0, 0, 40000, 73, 0, 0 }, + {3440,3440, 0, 0, 40000, 73, 0, 0 }, + {3441,3441, 0, 0, 40000, 73, 0, 0 }, + {3442,3442, 0, 0, 40000, 66, 0, 0 }, + {3443,3443, 0, 0, 40000, 73, 0, 0 }, + {3444,3444, 0, 0, 40000, 80, 0, 0 }, + {3445,3445, 0, 0, 40000, 66, 0, 0 }, + {3446,3446, 0, 0, 40000, 66, 0, 0 }, + {3447,3447, 0, 0, 40000, 66, 0, 0 }, + {3448,3448, 0, 0, 40000, 66, 0, 0 }, + {3449,3449, 0, 0, 40000, 80, 0, 0 }, + {3450,3450, 0, 0, 40000, 353, 0, 0 }, + {3451,3451, 0, 0, 40000, 0, 0, 0 }, + {3452,3452, 0, 0, 18440, 100, 0, 0 }, + {3453,3453, 0, 0, 18086, 100, 0, 0 }, + {3454,3454, 0, 0, 266, 66, 0, 0 }, + {3455,3455, 0, 0, 40000, 80, 0, 0 }, + {3456,3456, 0, 0, 40000, 100, 0, 0 }, + {3457,3457, 0, 0, 40000, 80, 0, 0 }, + {3458,3458, 0, 0, 40000, 120, 0, 0 }, + {3459,3459, 0, 0, 40000, 93, 0, 0 }, + {3460,3460, 0, 0, 40000, 233, 0, 0 }, + {3461,3461, 0, 0, 40000, 0, 0, 0 }, + {3462,3462, 0, 0, 40000, 86, 0, 0 }, + {3463,3463, 0, 0, 40000, 820, 0, 0 }, + {3464,3464, 0, 0, 40000, 4986, 0, 0 }, + {3465,3465, 0, 0, 40000, 146, 0, 0 }, + {3466,3466, 0, 0, 40000, 100, 0, 0 }, + {3467,3467, 0, 0, 40000, 3346, 0, 0 }, + {3468,3468, 0, 0, 40000, 660, 0, 0 }, + {3469,3469, 0, 0, 40000, 366, 0, 0 }, + {3470,3470, 0, 0, 40000, 1480, 0, 0 }, + {3471,3471, 0, 0, 40000, 646, 0, 0 }, + {3472,3472, 0, 0, 40000, 2673, 0, 0 }, + {3473,3473, 0, 0, 40000, 2500, 0, 0 }, + {3474,3474, 0, 0, 40000, 2513, 0, 0 }, + {3475,3475, 0, 0, 40000, 66, 0, 0 }, + {3476,3476, 0, 0, 9600, 1580, 0, 0 }, + {3477,3477, 0, 0, 40000, 46, 0, 0 }, + {3478,3478, 0, 0, 10673, 100, 0, 0 }, + {3479,3479, 0, 0, 2333, 800, 0, 0 }, + {3480,3480, 0, 0, 3673, 1200, 0, 0 }, + {3481,3481, 0, 0, 40000, 73, 0, 0 }, + {3482,3482, 0, 0, 40000, 146, 0, 0 }, + {3483,3483, 0, 0, 40000, 73, 0, 0 }, + {3484,3484, 0, 0, 2266, 726, 0, 0 }, + {3485,3485, 0, 0, 333, 140, 0, 0 }, + {3486,3486, 0, 0, 2286, 746, 0, 0 }, + {3487,3487, 0, 0, 293, 126, 0, 0 }, + {3488,3488, 0, 0, 3700, 1213, 0, 0 }, + {3489,3489, 0, 0, 3773, 1186, 0, 0 }, + {3490,3490, 0, 0, 3646, 1200, 0, 0 }, + {3491,3491, 0, 0, 3020, 73, 0, 0 }, + {3492,3492, 0, 0, 786, 273, 0, 0 }, + {3493,3493, 0, 0, 40000, 146, 0, 0 }, + {3494,3494, 0, 0, 40000, 3093, 0, 0 }, + {3495,3495, 0, 0, 273, 60, 0, 0 }, + {3496,3496, 0, 0, 40000, 73, 0, 0 }, + {3497,3497, 0, 0, 40000, 73, 0, 0 }, + {3498,3498, 0, 0, 40000, 3093, 0, 0 }, + {3499,3499, 0, 0, 40000, 240, 0, 0 }, + {3500,3500, 0, 2, 6, 0, 0, 0 }, + { 739, 739, 46, 0, 220, 33, 0, 0 }, + {3501,3501, 47, 0, 973, 93, 0, 0 }, + {3502,3502, 64, 0, 126, 66, 0, 0 }, + {3503,3503, 40, 0, 340, 146, 0, 0 }, + {3504,3504, 48, 0, 100, 26, 0, 0 }, + {3505,3505, 48, 0, 286, 133, 0, 0 }, + {3506,3506, 46, 0, 466, 166, 0, 0 }, + {3507,3507,111, 0, 226, 113, 0, 0 }, + {3508,3508, 49, 0, 473, 166, 0, 0 }, + {3509,3509, 56, 0, 126, 40, 0, 0 }, + {3510,3510, 52, 0, 520, 206, 0, 0 }, + {3511,3511, 96, 0, 1346, 473, 0, 0 }, + {3510,3510, 54, 0, 513, 206, 0, 0 }, + {3512,3512, 57, 0, 973, 266, 0, 0 }, + {3513,3513, 82, 0, 1580, 553, 0, 0 }, + {3510,3510, 60, 0, 506, 200, 0, 0 }, + {3514,3514, 60, 0, 1886, 646, 0, 0 }, + {3515,3515, 92, 0, 1026, 520, 0, 0 }, + {3516,3516, 60, 0, 180, 93, 0, 0 }, + {3517,3517, 58, 0, 213, 213, 0, 0 }, + {3518,3518, 22, 0, 2300, 766, 0, 0 }, + {3519,3519, 60, 0, 1873, 653, 0, 0 }, + {3520,3520, 72, 0, 260, 93, 0, 0 }, + {3521,3521, 77, 0, 253, 93, 0, 0 }, + {3522,3522, 70, 0, 206, 93, 0, 0 }, + {3523,3523, 75, 0, 173, 93, 0, 0 }, + {3524,3524, 69, 0, 406, 113, 0, 0 }, + {3525,3525, 59, 0, 380, 160, 0, 0 }, + {3526,3526, 48, 0, 373, 40, 0, 0 }, + {3527,3527, 89, 0, 433, 180, 0, 0 }, + {3528,3528, 84, 0, 813, 180, 0, 0 }, + {3529,3529, 33, 0, 240, 53, 0, 0 }, + {3530,3530, 55, 0, 220, 86, 0, 0 }, + {3531,3531, 58, 0, 526, 200, 0, 0 }, + {3532,3532, 52, 0, 526, 193, 0, 0 }, + {3533,3533, 57, 0, 166, 80, 0, 0 }, + {3534,3534, 57, 0, 240, 100, 0, 0 }, + {3535,3535, 85, 0, 220, 113, 0, 0 }, + {3536,3536, 68, 0, 173, 93, 0, 0 }, + {3536,3536, 61, 0, 220, 113, 0, 0 }, + {3537,3537, 64, 0, 346, 53, 0, 0 }, + {3538,3538, 44, 0, 1080, 346, 0, 0 }, + {3539,3539,100, 0, 193, 20, 0, 0 }, + {3540,3540,100, 0, 793, 26, 0, 0 }, + {3541,3541, 0, 0, 14166, 320, 0, 0 }, + {3542,3542, 0, 0, 3873, 1613, 0, 0 }, + {3543,3543, 0, 0, 3586, 86, 0, 0 }, + {3544,3544, 0, 0, 7406, 2486, 0, 0 }, + {3545,3545, 0, 0, 4640, 1560, 0, 0 }, + {3546,3546, 0, 0, 446, 440, 0, 0 }, + {3547,3547, 0, 0, 9253, 3100, 0, 0 }, + {3548,3548, 0, 0, 4646, 646, 0, 0 }, + {3549,3549, 0, 0, 40000, 66, 0, 0 }, + {3550,3550, 0, 0, 40000, 73, 0, 0 }, + {3551,3551, 0, 0, 40000, 113, 0, 0 }, + {3552,3552, 0, 0, 40000, 73, 0, 0 }, + {3553,3553, 0, 0, 40000, 73, 0, 0 }, + {3554,3554, 0, 0, 40000, 0, 0, 0 }, + {3555,3555, 0, 0, 40000, 60, 0, 0 }, + {3556,3556, 0, 0, 3673, 1206, 0, 0 }, + {3557,3557, 0, 0, 3706, 1293, 0, 0 }, + {3558,3558, 0, 0, 5693, 1126, 0, 0 }, + {3559,3559, 0, 0, 2406, 846, 0, 0 }, + {3560,3560, 0, 0, 40000, 66, 0, 0 }, + {3561,3561, 0, 0, 40000, 73, 0, 0 }, + {3562,3562, 0, 0, 4333, 13, 0, 0 }, + {3563,3563, 0, 0, 3700, 66, 0, 0 }, + {3564,3564, 0, 0, 40000, 0, 0, 0 }, + {3565,3565, 0, 0, 3713, 1260, 0, 0 }, + {3566,3566, 0, 0, 1140, 126, 0, 0 }, + {3567,3567, 0, 0, 40000, 186, 0, 0 }, + {3568,3568, 0, 0, 40000, 0, 0, 0 }, + {3569,3569, 0, 0, 14400, 6, 0, 0 }, + {3570,3570, 0, 0, 14580, 66, 0, 0 }, + {3571,3571, 0, 0, 40000, 73, 0, 0 }, + {3572,3572, 0, 0, 40000, 353, 0, 0 }, + {3573,3573, 0, 0, 40000, 0, 0, 0 }, + {3574,3574, 0, 0, 40000, 173, 0, 0 }, + {3575,3575, 0, 0, 1833, 600, 0, 0 }, + {3576,3576, 0, 0, 40000, 0, 0, 0 }, + {3577,3577, 0, 0, 40000, 206, 0, 0 }, + {3578,3578, 0, 0, 40000, 46, 0, 0 }, + {3579,3579, 0, 0, 40000, 73, 0, 0 }, + {3580,3580, 0, 0, 9166, 2900, 0, 0 }, + {3581,3581, 0, 0, 5640, 680, 0, 0 }, + {3582,3582, 0, 0, 640, 220, 0, 0 }, + {3583,3583, 0, 0, 40000, 53, 0, 0 }, + {3584,3584, 0, 0, 40000, 26, 0, 0 }, + {3585,3585, 0, 0, 40000, 0, 0, 0 }, + {3586,3586, 0, 0, 40000, 66, 0, 0 }, + {3587,3587, 0, 0, 40000, 60, 0, 0 }, + {3588,3588, 0, 0, 40000, 0, 0, 0 }, + {3589,3589, 0, 0, 40000, 73, 0, 0 }, + {3590,3590, 0, 0, 40000, 0, 0, 0 }, + {3591,3591, 0, 0, 40000, 0, 0, 0 }, + {3592,3592, 0, 0, 3780, 73, 0, 0 }, + {3593,3593, 0, 0, 40000, 0, 0, 0 }, + {3594,3594, 0, 0, 3786, 73, 0, 0 }, + {3595,3595, 0, 0, 40000, 73, 0, 0 }, + {3596,3596, 0, 0, 40000, 66, 0, 0 }, + {3597,3597, 0, 0, 40000, 73, 0, 0 }, + {3598,3598, 0, 0, 40000, 53, 0, 0 }, + {3599,3599, 0, 0, 40000, 426, 0, 0 }, + {3600,3600, 0, 0, 40000, 133, 0, 0 }, + {3601,3601, 0, 0, 40000, 66, 0, 0 }, + {3602,3602, 0, 0, 40000, 433, 0, 0 }, + {3603,3603, 0, 0, 393, 126, 0, 0 }, + {3604,3604, 0, 0, 40000, 66, 0, 0 }, + {3605,3605, 0, 0, 40000, 353, 0, 0 }, + {3606,3606, 0, 0, 3813, 73, 0, 0 }, + {3607,3607, 0, 0, 5793, 780, 0, 0 }, + {3608,3608, 0, 0, 40000, 73, 0, 0 }, + {3609,3609, 0, 0, 40000, 86, 0, 0 }, + {3610,3610, 0, 0, 820, 206, 0, 0 }, + {3611,3611, 0, 0, 40000, 66, 0, 0 }, + {3612,3612, 0, 0, 40000, 200, 0, 0 }, + {3613,3613, 0, 0, 18186, 720, 0, 0 }, + {3614,3614, 0, 0, 40000, 0, 0, 0 }, + {3615,3615, 0, 0, 40000, 493, 0, 0 }, + {3616,3616, 0, 0, 40000, 306, 0, 0 }, + {3617,3617, 0, 0, 2166, 600, 0, 0 }, + {3618,3618, 0, 0, 40000, 73, 0, 0 }, + {3619,3619, 0, 0, 40000, 3073, 0, 0 }, + {3620,3620, 0, 0, 2333, 413, 0, 0 }, + {3621,3621, 0, 0, 14880, 73, 0, 0 }, + {3622,3622, 0, 0, 40000, 66, 0, 0 }, + {3623,3623, 0, 0, 40000, 73, 0, 0 }, + {3624,3624, 0, 0, 40000, 1873, 0, 0 }, + {3625,3625, 0, 0, 40000, 446, 0, 0 }, + {3626,3626, 0, 0, 40000, 3126, 0, 0 }, + {3627,3627, 0, 0, 18446, 6140, 0, 0 }, + {3628,3628, 0, 0, 1113, 240, 0, 0 }, + {3629,3629, 0, 0, 40000, 3600, 0, 0 }, + {3630,3630, 0, 0, 40000, 4726, 0, 0 }, + {3631,3631, 0, 0, 40000, 0, 0, 0 }, + {3632,3632, 0, 0, 2893, 606, 0, 0 }, + {3633,3633, 0, 0, 40000, 0, 0, 0 }, + {3634,3634, 0, 0, 40000, 0, 0, 0 }, + {3635,3635, 0, 0, 40000, 173, 0, 0 }, + {3636,3636, 0, 0, 40000, 60, 0, 0 }, + {3637,3637, 0, 0, 40000, 0, 0, 0 }, + {3638,3638, 0, 0, 986, 326, 0, 0 }, + {3639,3639, 0, 0, 1873, 646, 0, 0 }, + {3640,3640, 0, 0, 200, 260, 0, 0 }, + {3641,3641, 0, 0, 1180, 393, 0, 0 }, + {3642,3642, 0, 0, 266, 160, 0, 0 }, + {3643,3643, 0, 0, 313, 126, 0, 0 }, + {3644,3644, 0, 0, 406, 253, 0, 0 }, + {3645,3645, 0, 0, 1013, 813, 0, 0 }, + {3646,3646, 0, 0, 273, 53, 0, 0 }, + {3647,3647, 0, 0, 720, 213, 0, 0 }, + {3648,3648, 0, 0, 386, 120, 0, 0 }, + {3649,3649, 0, 0, 40000, 766, 0, 0 }, + {3650,3650, 0, 0, 40000, 66, 0, 0 }, + {3651,3651, 0, 0, 40000, 73, 0, 0 }, + {3652,3652, 0, 0, 1186, 426, 0, 0 }, + {3653,3653, 0, 0, 16720, 240, 0, 0 }, + {3654,3654, 0, 0, 8026, 246, 0, 0 }, + {3655,3655, 0, 0, 18186, 140, 0, 0 }, + {3656,3656, 0, 0, 14566, 200, 0, 0 }, + {3657,3657, 0, 0, 7973, 20, 0, 0 }, + {3658,3658, 0, 0, 4446, 86, 0, 0 }, + {3659,3659, 0, 0, 4473, 100, 0, 0 }, + {3660,3660, 0, 0, 8646, 153, 0, 0 }, + {3661,3661, 0, 0, 3726, 660, 0, 0 }, + {3662,3662, 0, 0, 1893, 653, 0, 0 }, + {3663,3663, 0, 0, 1933, 760, 0, 0 }, + {3664,3664, 0, 0, 9160, 240, 0, 0 }, + {3665,3665, 0, 0, 1133, 100, 0, 0 }, + {3666,3666, 0, 0, 633, 233, 0, 0 }, + {3667,3667, 0, 0, 9153, 3060, 0, 0 }, + {3668,3668, 0, 0, 2166, 406, 0, 0 }, + {3669,3669, 0, 0, 40000, 66, 0, 0 }, + {3670,3670, 0, 0, 40000, 73, 0, 0 }, + {3671,3671, 0, 0, 40000, 73, 0, 0 }, + {3672,3672, 0, 0, 40000, 73, 0, 0 }, + {3673,3673, 0, 0, 40000, 346, 0, 0 }, + {3674,3674, 0, 0, 40000, 353, 0, 0 }, + {3675,3675, 0, 0, 40000, 200, 0, 0 }, + {3676,3676, 0, 0, 40000, 320, 0, 0 }, + {3677,3677, 0, 0, 4646, 100, 0, 0 }, + {3678,3678, 0, 0, 4426, 133, 0, 0 }, + {3679,3679, 0, 0, 4633, 100, 0, 0 }, + {3680,3680, 0, 0, 2266, 133, 0, 0 }, + {3681,3681, 0, 0, 2346, 53, 0, 0 }, + {3682,3682, 0, 0, 40000, 66, 50, 0 }, + {3683,3683, 0, 0, 9686, 173, 20, 0 }, + {3684,3684, 0, 0, 14300, 66, 0, 0 }, + {3685,3685, 0, 0, 40000, 0, 0, 0 }, + {3686,3686, 0, 0, 40000, 0, 0, 0 }, + {3687,3687, 0, 0, 40000, 0, 0, 0 }, + {3688,3688, 0, 0, 8613, 73, 0, 0 }, + {3689,3689, 0, 0, 40000, 0, 0, 0 }, + {3690,3690, 0, 0, 40000, 0, 0, 0 }, + {3691,3691, 0, 0, 40000, 0, 0, 0 }, + {3692,3692, 0, 0, 40000, 0, 0, 0 }, + {3693,3693, 0, 0, 40000, 393, 0, 0 }, + {3694,3694, 0, 0, 40000, 126, 0, 0 }, + {3695,3695, 0, 0, 40000, 120, 0, 0 }, + {3696,3696, 0, 0, 40000, 0, 0, 0 }, + {3697,3697, 0, 0, 40000, 226, 0, 0 }, + {3698,3698, 0, 0, 7420, 1186, 0, 0 }, + {3699,3699, 0, 0, 3280, 1726, 0, 0 }, + {3700,3700, 0, 0, 3680, 1220, 0, 0 }, + {3701,3701, 0, 0, 40000, 480, 0, 0 }, + {3702,3702, 0, 0, 40000, 306, 0, 0 }, + {3703,3703, 0, 0, 40000, 433, 0, 0 }, + {3704,3704, 0, 0, 40000, 133, 0, 0 }, + {3705,3705, 0, 0, 40000, 0, 0, 0 }, + {3706,3706, 0, 0, 40000, 0, 0, 0 }, + {3707,3707, 0, 0, 1166, 380, 0, 0 }, + {3708,3708, 0, 0, 40000, 140, 0, 0 }, + {3709,3709, 0, 0, 40000, 126, 0, 0 }, + {3710,3710, 0, 0, 40000, 100, 0, 0 }, + {3711,3711, 0, 0, 40000, 66, 0, 0 }, + {3712,3712, 0, 0, 40000, 226, 0, 0 }, + {3713,3713, 0, 0, 40000, 133, 0, 0 }, + {3714,3714, 0, 0, 40000, 73, 0, 0 }, + {3715,3715, 0, 0, 40000, 226, 0, 0 }, + {3716,3716, 0, 0, 40000, 100, 0, 0 }, + {3717,3717, 0, 0, 40000, 80, 0, 0 }, + {3718,3718, 0, 0, 40000, 100, 0, 0 }, + {3719,3719, 0, 0, 40000, 73, 0, 0 }, + {3720,3720, 0, 0, 40000, 73, 0, 0 }, + {3721,3721, 0, 0, 40000, 73, 0, 0 }, + {3722,3722, 0, 0, 40000, 126, 0, 0 }, + {3723,3723, 0, 0, 40000, 80, 0, 0 }, + {3724,3724, 0, 0, 40000, 73, 0, 0 }, + {3725,3725, 0, 0, 40000, 86, 0, 0 }, + {3726,3726, 0, 0, 40000, 100, 0, 0 }, + {3727,3727, 0, 0, 40000, 0, 0, 0 }, + {3728,3728, 0, 0, 40000, 126, 0, 0 }, + {3729,3729, 0, 0, 40000, 133, 0, 0 }, + {3730,3730, 0, 0, 40000, 140, 0, 0 }, + {3731,3731, 0, 0, 40000, 73, 0, 0 }, + {3732,3732, 0, 0, 40000, 60, 0, 0 }, + {3733,3733, 0, 0, 40000, 93, 0, 0 }, + {3734,3734, 0, 0, 40000, 80, 0, 0 }, + {3735,3735, 0, 0, 40000, 66, 0, 0 }, + {3736,3736, 0, 0, 40000, 0, 0, 0 }, + {3737,3737, 0, 0, 40000, 220, 0, 0 }, + {3738,3738, 0, 0, 40000, 80, 0, 0 }, + {3739,3739, 0, 0, 40000, 400, 0, 0 }, + {3740,3740, 0, 0, 40000, 1373, 0, 0 }, + {3741,3741, 0, 0, 40000, 86, 0, 0 }, + {3742,3742, 0, 0, 40000, 1313, 0, 0 }, + {3743,3743, 0, 0, 40000, 0, -50, 0 }, + {3744,3744, 0, 0, 11486, 593, 0, 0 }, + {3745,3745, 0, 0, 40000, 1246, 0, 0 }, + {3746,3746, 0, 0, 40000, 140, -20, 0 }, + {3747,3747, 0, 0, 14386, 2680, 0, 0 }, + {3748,3748, 0, 0, 40000, 653, 0, 0 }, + {3749,3749, 0, 0, 2286, 713, 0, 0 }, + {3750,3750, 0, 0, 40000, 253, 0, 0 }, + {3751,3751, 0, 0, 6933, 406, 0, 0 }, + {3752,3752, 0, 0, 40000, 1313, 0, 0 }, + {3753,3753, 0, 0, 40000, 1440, 0, 0 }, + {3754,3754, 0, 0, 40000, 73, 0, 0 }, + {3755,3755, 0, 0, 11100, 420, 0, 0 }, + {3756,3756, 0, 0, 6493, 320, 0, 0 }, + {3757,3757, 0, 0, 3486, 126, 0, 0 }, + {3758,3758, 0, 0, 6620, 2133, 0, 0 }, + {3759,3759, 0, 0, 1180, 413, 0, 0 }, + {3760,3760, 0, 0, 40000, 73, 0, 0 }, + {3761,3761, 0, 0, 40000, 73, 0, 0 }, + {3762,3762, 0, 0, 40000, 66, 0, 0 }, + {3763,3763, 0, 0, 4580, 413, 0, 0 }, + {3764,3764, 0, 0, 340, 146, 0, 0 }, + {3765,3765, 0, 0, 1166, 400, 0, 0 }, + {3766,3766, 0, 0, 1346, 660, 0, 0 }, + {3767,3767, 0, 0, 1260, 393, 0, 0 }, + {3768,3768, 0, 0, 3646, 1186, 0, 0 }, + {3769,3769, 0, 0, 2713, 400, 0, 0 }, + {3770,3770, 0, 0, 1780, 73, 0, 0 }, + {3771,3771, 0, 0, 800, 213, 0, 0 }, + {3772,3772, 0, 0, 660, 173, 0, 0 }, + {3773,3773, 0, 0, 12146, 73, 0, 0 }, + {3774,3774, 0, 0, 273, 60, 0, 0 }, + {3775,3775, 0, 0, 40000, 73, 0, 0 }, + {3776,3776, 0, 0, 380, 53, 0, 0 }, + {3777,3777, 0, 0, 40000, 200, 0, 0 }, + {3778,3778, 0, 0, 586, 20, 0, 0 }, + {3779,3779, 0, 2, 6, 0, 40, 0 }, + { 738, 738, 44, 0, 840, 340, 33, 0 }, + {3780,3780, 36, 0, 7366, 140, 33, 0 }, + {3781,3781, 32, 0, 100, 40, 40, 0 }, + {2030,2030, 60, 0, 293, 126, 50, 0 }, + {3782,3782, 24, 0, 100, 0, 40, 0 }, + {3783,3783, 60, 0, 126, 73, 50, 0 }, + {3784,3784, 44, 0, 393, 93, 50, 0 }, + { 132, 132, 44, 0, 173, 100, 40, 0 }, + {3785,3785, 47, 0, 393, 93, 50, 0 }, + { 152, 152, 44, 0, 213, 86, 40, 0 }, + {3784,3784, 50, 0, 393, 93, 50, 0 }, + { 139, 139, 44, 0, 293, 100, 40, 0 }, + {3784,3784, 54, 0, 393, 93, 50, 0 }, + {3784,3784, 57, 0, 393, 93, 50, 0 }, + {3786,3786, 60, 0, 1900, 666, 40, 0 }, + {3784,3784, 60, 0, 393, 93, 50, 0 }, + {3514,3514, 60, 0, 1886, 646, 30, 0 }, + {3787,3787, 60, 0, 1900, 666, 45, 0 }, + {3788,3788, 60, 0, 1886, 666, 30, 0 }, + {3516,3516, 60, 0, 180, 93, 40, 0 }, + {3789,3789, 60, 0, 1866, 653, 40, 0 }, + {3517,3517, 58, 0, 213, 213, 40, 0 }, + {3790,3790, 60, 0, 1873, 633, 40, 0 }, + {3791,3791, 44, 0, 946, 333, 40, 0 }, + {3519,3519, 60, 0, 1873, 653, 20, 0 }, + {2037,2037, 44, 0, 213, 126, 40, 0 }, + { 144, 144, 44, 0, 213, 126, 40, 0 }, + {2038,2038, 44, 0, 106, 46, 40, 0 }, + {3792,3792, 44, 0, 380, 360, 40, 0 }, + {3793,3793, 44, 0, 520, 206, 40, 0 }, + {3794,3794, 45, 0, 273, 100, 40, 0 }, + {3795,3795, 33, 0, 326, 106, 40, 0 }, + {3796,3796, 56, 0, 506, 200, 40, 0 }, + {3796,3796, 51, 0, 506, 200, 40, 0 }, + {3530,3530, 55, 0, 220, 86, 40, 0 }, + {3797,3797, 44, 0, 126, 66, 40, 0 }, + {3798,3798, 44, 0, 553, 186, 40, 0 }, + {3533,3533, 57, 0, 166, 80, 40, 0 }, + {3534,3534, 56, 0, 240, 100, 40, 0 }, + { 158, 158, 68, 0, 126, 140, 40, 0 }, + {3799,3799, 51, 0, 513, 206, 40, 0 }, + {3800,3800, 46, 0, 506, 200, 40, 0 }, + {3537,3537, 64, 0, 346, 53, 40, 0 }, + {3538,3538, 44, 0, 1080, 346, 40, 0 }, + {3801,3801, 44, 0, 513, 206, 40, 0 }, + {3802,3802, 44, 0, 3720, 1260, 40, 0 }, + { 152, 152, 45, 0, 220, 80, 20, 0 }, + {3683,3683, 0, 0, 9686, 173, 50, 0 }, + {3803,3803, 0, 0, 40000, 86, 20, 0 }, + {3804,3804, 0, 0, 40000, 226, 0, 0 }, + {3712,3712, 0, 0, 40000, 226, 50, 0 }, + {3805,3805, 0, 0, 40000, 73, 0, 0 }, + {3806,3806, 0, 0, 40000, 73, 0, 0 }, + {3807,3807, 0, 0, 40000, 93, 0, 0 }, + {3808,3808, 0, 0, 4653, 660, -18, 0 }, + {3809,3809, 0, 0, 6686, 2246, 10, 0 }, + {3810,3810, 0, 0, 1180, 413, 0, 0 }, + {3811,3811, 0, 0, 966, 293, 30, 0 }, + {3812,3812, 0, 0, 1780, 66, 0, 0 }, + {3780,3780, 45, 0, 5900, 113, 20, 0 }, + {3061,3061, 45, 0, 40000, 0, 40, 0 }, + {3813,3813, 60, 0, 126, 226, 60, 0 }, + {3781,3781, 60, 0, 93, 33, 60, 0 }, + {3814,3814, 44, 0, 393, 86, 50, 0 }, + {3815,3815, 57, 0, 166, 80, 127, 0 }, + {3816,3816, 56, 0, 240, 100, 127, 0 }, + {3817,3817, 60, 0, 113, 26, 60, 0 }, + {3818,3818, 60, 0, 113, 26, 60, 0 }, + {3061,3061, 45, 0, 40000, 0, 20, 0 }, + {3517,3517, 45, 0, 213, 213, 20, 0 }, + {3819,3819, 0, 0, 4033, 100, 0, 0 }, + {3820,3820, 0, 0, 5200, 873, 0, 0 }, + {3821,3821, 0, 0, 40000, 0, 0, 0 }, + {3822,3822, 0, 0, 10493, 160, 0, 0 }, + {3823,3823, 0, 0, 40000, 740, 0, 0 }, + {3824,3825, 0, 1, 40000, 366, 0, 0.078125 }, + {3826,3826, 0, 0, 40000, 5100, 0, 0 }, + {3827,3827, 0, 0, 40000, 766, 0, 0 }, + {3828,1172, 0, 1, 40000, 780, 0, 0.15625 }, + {3829,3829, 0, 0, 40000, 60, 0, 0 }, + {3830,3830, 0, 0, 566, 133, 0, 0 }, + {3831,3831, 32, 0, 146, 33, 0, 0 }, + {3832,3832, 36, 0, 273, 140, 0, 0 }, + {3833,3833, 88, 0, 340, 120, 0, 0 }, + {3834,3834, 0, 0, 9006, 240, 0, 0 }, + {3835,3835, 0, 0, 9206, 246, 0, 0 }, + {3836,3836, 0, 0, 9246, 386, 0, 0 }, + {3837,3837, 0, 0, 9440, 220, 0, 0 }, + {3838,3838, 0, 0, 8900, 133, 0, 0 }, + {3839,3839, 0, 0, 9400, 253, 0, 0 }, + {3840,3840, 0, 0, 4613, 420, 0, 0 }, + {3841,3841, 0, 0, 9233, 426, 0, 0 }, + {3842,3842, 0, 0, 40000, 526, 0, 0 }, + {3843,3843, 0, 0, 40000, 640, 0, 0 }, + {3844,3844, 0, 0, 40000, 666, 0, 0 }, + {3845,3845, 0, 0, 40000, 1053, 0, 0 }, + {3846,3846, 0, 0, 40000, 173, 0, 0 }, + {3847,3847, 0, 0, 40000, 246, 0, 0 }, + {3848,3848, 0, 0, 40000, 226, 0, 0 }, + {3849,3849, 0, 0, 4073, 233, 0, 0 }, + {3850,3850, 0, 0, 14286, 326, 0, 0 }, + {3851,3851, 0, 0, 9233, 146, 0, 0 }, + {3852,3852, 0, 0, 4480, 133, 0, 0 }, + {3853,3853, 0, 0, 40000, 53, 0, 0 }, + {3854,3854, 0, 0, 40000, 126, 0, 0 }, + {3855,3855, 0, 0, 40000, 126, 0, 0 }, + {3856,3856, 0, 0, 18226, 146, 0, 0 }, + {3857,3857, 0, 0, 40000, 326, 0, 0 }, + {3858,3858, 0, 0, 40000, 0, 0, 0 }, + {3859,3859, 0, 0, 40000, 300, 0, 0 }, + {3860,3860, 0, 0, 40000, 0, 0, 0 }, + {3861,3861, 0, 0, 40000, 0, 0, 0 }, + {3862,3862, 0, 0, 40000, 0, 0, 0 }, + {3863,3863, 0, 0, 40000, 140, 0, 0 }, + {3864,3864, 0, 0, 40000, 153, 0, 0 }, + {3865,3865, 0, 0, 40000, 233, 0, 0 }, + {3866,3866, 0, 0, 40000, 186, 0, 0 }, + {3867,3867, 0, 0, 40000, 413, 0, 0 }, + {3868,3868, 0, 0, 40000, 373, 0, 0 }, + {3869,3869, 0, 0, 1246, 440, 0, 0 }, + {3870,3870, 0, 0, 4620, 1513, 0, 0 }, + {3871,3871, 0, 0, 40000, 433, 0, 0 }, + {3872,3872, 0, 0, 40000, 453, 0, 0 }, + {3873,3873, 0, 0, 40000, 1440, 0, 0 }, + {3874,3874, 0, 0, 40000, 480, 0, 0 }, + {3875,3875, 0, 0, 40000, 1360, 0, 0 }, + {3876,3876, 0, 0, 40000, 0, 0, 0 }, + {3877,3877, 0, 0, 40000, 353, 0, 0 }, + {3878,3878, 0, 0, 40000, 86, 0, 0 }, + {3879,3879, 0, 0, 40000, 126, 0, 0 }, + {3880,3880, 0, 0, 40000, 73, 0, 0 }, + {3881,3881, 0, 0, 40000, 80, 0, 0 }, + {3882,3882, 0, 0, 40000, 246, 0, 0 }, + {3883,3883, 0, 0, 40000, 93, 0, 0 }, + {3884,3884, 0, 0, 40000, 120, 0, 0 }, + {3885,3885, 0, 0, 40000, 180, 0, 0 }, + {3886,3886, 0, 0, 40000, 133, 0, 0 }, + {3887,3887, 0, 0, 40000, 133, 0, 0 }, + {3888,3888, 0, 0, 40000, 153, 0, 0 }, + {3889,3889, 0, 0, 40000, 93, 0, 0 }, + {3890,3890, 0, 0, 40000, 140, 0, 0 }, + {3891,3891, 0, 0, 40000, 100, 0, 0 }, + {3892,3892, 0, 0, 40000, 146, 0, 0 }, + {3893,3893, 0, 0, 40000, 126, 0, 0 }, + {3894,3894, 0, 0, 40000, 160, 0, 0 }, + {3895,3895, 0, 0, 40000, 226, 0, 0 }, + {3896,3896, 0, 0, 40000, 140, 0, 0 }, + {3897,3897, 0, 0, 40000, 200, 0, 0 }, + {3898,3898, 0, 0, 40000, 66, 0, 0 }, + {3899,3899, 0, 0, 40000, 446, 0, 0 }, + {3900,3900, 0, 0, 40000, 140, 0, 0 }, + {3901,3901, 0, 0, 40000, 400, 0, 0 }, + {3902,3902, 0, 0, 40000, 373, 0, 0 }, + {3903,3903, 0, 0, 40000, 1306, 0, 0 }, + {3904,3904, 0, 0, 40000, 186, 0, 0 }, + {3905,3905, 0, 0, 40000, 640, 0, 0 }, + {3906,3906, 0, 0, 40000, 346, 0, 0 }, + {3907,3907, 0, 0, 40000, 140, 0, 0 }, + {3908,3908, 0, 0, 40000, 253, 0, 0 }, + {3909,3909, 0, 0, 8980, 746, 0, 0 }, + {3910,3910, 0, 0, 40000, 1266, 0, 0 }, + {3911,3911, 0, 0, 40000, 1306, 0, 0 }, + {3912,3912, 0, 0, 7226, 593, 0, 0 }, + {3913,3913, 0, 0, 40000, 140, 0, 0 }, + {3914,3914, 0, 0, 40000, 220, 0, 0 }, + {3915,3915, 0, 0, 40000, 146, 0, 0 }, + {3916,3916, 0, 0, 4606, 1506, 0, 0 }, + {3917,3917, 0, 0, 40000, 80, 0, 0 }, + {3918,3918, 0, 0, 40000, 0, 0, 0 }, + {3919,3919, 0, 0, 40000, 0, 0, 0 }, + {3920,3920, 0, 0, 613, 226, 0, 0 }, + {3921,3921, 0, 0, 9073, 2946, 0, 0 }, + {3922,3922, 0, 0, 40000, 73, 0, 0 }, + {3923,3923, 0, 0, 3726, 200, 0, 0 }, + {3924,3924, 0, 0, 3680, 373, 0, 0 }, + {3925,3925, 0, 0, 7113, 186, 0, 0 }, + {3926,3926, 0, 0, 2406, 106, 0, 0 }, + {3927,3927, 0, 0, 40000, 0, 0, 0 }, + {3928,3928, 0, 0, 40000, 253, 0, 0 }, + {3929,3929, 0, 0, 40000, 0, 0, 0 }, + {3930,3930, 0, 0, 40000, 80, 0, 0 }, + {3931,3931, 0, 0, 40000, 86, 0, 0 }, + {3932,3932, 0, 0, 18186, 740, 0, 0 }, + {3933,3933, 0, 0, 18426, 813, 0, 0 }, + { 523, 523, 0, 0, 200, 260, 0, 0 }, + {3934,3934, 0, 0, 340, 146, 0, 0 }, + {3935,3935, 0, 0, 366, 260, 0, 0 }, + {3936,3936, 48, 0, 126, 26, 0, 0 }, + {3937,3937, 27, 0, 200, 106, 0, 0 }, + {3938,3938, 40, 0, 1073, 800, 0, 0 }, + {3939,3939, 48, 0, 100, 33, 0, 0 }, + {3938,3938, 45, 0, 933, 666, 0, 0 }, + {3940,3940, 48, 0, 140, 333, 0, 0 }, + {3938,3938, 47, 0, 933, 666, 0, 0 }, + {3941,3941, 48, 0, 1840, 1373, 0, 0 }, + {3938,3938, 49, 0, 953, 686, 0, 0 }, + {3938,3938, 53, 0, 906, 686, 0, 0 }, + {3938,3938, 56, 0, 913, 693, 0, 0 }, + { 129, 129, 52, 0, 293, 126, 0, 0 }, + { 130, 130, 48, 0, 173, 93, 0, 0 }, + { 129, 129, 58, 0, 286, 126, 0, 0 }, + { 132, 132, 47, 0, 173, 100, 0, 0 }, + { 492, 492, 43, 0, 820, 306, 0, 0 }, + { 132, 132, 49, 0, 173, 93, 0, 0 }, + { 132, 132, 51, 0, 173, 93, 0, 0 }, + { 132, 132, 54, 0, 173, 93, 0, 0 }, + { 132, 132, 57, 0, 146, 86, 0, 0 }, + { 492, 492, 72, 0, 706, 300, 0, 0 }, + { 137, 137, 76, 0, 1900, 666, 0, 0 }, + { 138, 138, 84, 0, 740, 300, 0, 0 }, + { 139, 139, 36, 0, 353, 146, 0, 0 }, + { 140, 140, 76, 0, 1886, 680, 0, 0 }, + { 141, 141, 84, 0, 220, 113, 0, 0 }, + { 135, 135, 83, 0, 1353, 480, 0, 0 }, + { 142, 142, 84, 0, 386, 160, 0, 0 }, + {3942,3942, 24, 0, 2313, 780, 0, 0 }, + { 137, 137, 77, 0, 1893, 660, 0, 0 }, + { 144, 144, 60, 0, 213, 126, 0, 0 }, + { 145, 145, 65, 0, 180, 146, 0, 0 }, + { 146, 146, 59, 0, 173, 93, 0, 0 }, + { 147, 147, 51, 0, 266, 213, 0, 0 }, + { 148, 148, 45, 0, 513, 200, 0, 0 }, + { 149, 149, 71, 0, 246, 26, 0, 0 }, + { 150, 150, 60, 0, 500, 193, 0, 0 }, + { 151, 151, 58, 0, 513, 200, 0, 0 }, + { 152, 152, 53, 0, 220, 86, 0, 0 }, + { 153, 153, 64, 0, 113, 40, 0, 0 }, + { 154, 154, 71, 0, 840, 300, 0, 0 }, + { 156, 156, 61, 0, 166, 80, 0, 0 }, + { 158, 158, 48, 0, 173, 213, 0, 0 }, + { 159, 159, 69, 0, 126, 140, 0, 0 }, + { 160, 160, 68, 0, 126, 140, 0, 0 }, + { 161, 161, 63, 0, 326, 113, 0, 0 }, + { 162, 162, 74, 0, 860, 286, 0, 0 }, + { 163, 163, 60, 0, 386, 160, 0, 0 }, + { 164, 164, 80, 0, 1106, 273, 0, 0 }, + { 165, 165, 64, 0, 126, 66, 0, 0 }, + { 166, 166, 69, 0, 386, 80, 0, 0 }, + { 167, 167, 73, 0, 546, 306, 0, 0 }, + { 168, 168, 75, 0, 126, 140, 0, 0 }, + { 169, 169, 68, 0, 340, 320, 0, 0 }, + { 131, 131, 48, 0, 520, 200, 0, 0 }, + {3061,3061, 53, 0, 40000, 0, 0, 0 }, + {3943,3944, 0, 4, 2133, 333, 0, 0 }, + {3945,3946, 0, 4, 8966, 393, 0, 0 }, + { 174,3947, 0, 4, 6946, 320, 0, 0 }, + {3948,3949, 0, 4, 9320, 133, 0, 0 }, + { 9,3950, 0, 4, 1606, 426, 0, 0 }, + {3951,3952, 0, 4, 18373, 240, 0, 0 }, + {3953,3954, 0, 1, 7440, 1100, 0, 0.0625 }, + { 15,3955, 0, 4, 5640, 1986, 0, 0 }, + {3956,3957, 0, 4, 40000, 100, 0, 0 }, + {3958,3959, 0, 4, 40000, 73, 0, 0 }, + {3960,3961, 0, 4, 40000, 73, 0, 0 }, + {3962,3963, 0, 4, 40000, 73, 0, 0 }, + {3964,3965, 0, 4, 18186, 153, 0, 0 }, + {3966,3967, 0, 4, 18453, 153, 0, 0 }, + { 31,3968, 0, 4, 40000, 0, 0, 0 }, + {3969,3970, 0, 4, 17886, 100, 0, 0 }, + {3971,3972, 0, 4, 40000, 66, 0, 0 }, + {3973,3972, 0, 4, 40000, 66, 0, 0 }, + {3974,3975, 0, 4, 40000, 46, 0, 0 }, + {3976,3977, 0, 4, 18553, 106, 0, 0 }, + {3978,3977, 0, 4, 18460, 106, 0, 0 }, + {3979,3980, 0, 4, 9366, 106, 0, 0 }, + {3981,3982, 0, 4, 9073, 226, 0, 0 }, + {3983,3984, 0, 4, 40000, 140, 0, 0 }, + {3985,3986, 0, 4, 40000, 800, 0, 0 }, + { 54,3987, 0, 4, 2513, 706, 0, 0 }, + {3988,3989, 0, 4, 40000, 86, 0, 0 }, + {3990,3990, 0, 0, 40000, 126, 0, 0 }, + {3991,3992, 0, 4, 40000, 233, 0, 0 }, + {3993, 253, 0, 4, 40000, 66, 0, 0 }, + {3994,3995, 0, 4, 40000, 0, 0, 0 }, + {3996,3997, 0, 4, 40000, 126, 0, 0 }, + {3998,3999, 0, 4, 40000, 80, 0, 0 }, + {4000,4001, 0, 4, 40000, 73, 0, 0 }, + {4002,4003, 0, 1, 40000, 86, 0, 0.046875 }, + {4004,4005, 0, 4, 40000, 86, 0, 0 }, + {1503,4006, 0, 4, 40000, 93, 0, 0 }, + { 88,4007, 0, 4, 40000, 1220, 0, 0 }, + {3743,4008, 0, 4, 7646, 1260, 0, 0 }, + { 92,4009, 0, 4, 40000, 186, 0, 0 }, + { 93,4010, 0, 4, 40000, 813, 0, 0 }, + { 94,4011, 0, 4, 7660, 1260, 0, 0 }, + { 96,4012, 0, 4, 40000, 2460, 0, 0 }, + {4013,4014, 0, 4, 40000, 420, 0, 0 }, + { 103,4015, 0, 4, 3673, 1240, 0, 0 }, + {4016,4017, 0, 1, 6286, 380, 0, 0 }, + {4018,4019, 0, 1, 2220, 426, 0, 0.03125 }, + { 107,4020, 0, 4, 2086, 760, 0, 0 }, + {4021,4022, 0, 1, 40000, 100, 0, 0.0625 }, + { 110,4023, 0, 4, 40000, 100, 0, 0 }, + { 111,4024, 0, 4, 2300, 820, 0, 0 }, + {4025,4026, 0, 4, 1013, 326, 0, 0 }, + {4027,4028, 0, 1, 1220, 393, 0, 0.03125 }, + { 115,4029, 0, 4, 1813, 646, 0, 0 }, + {4030,4031, 0, 1, 566, 146, 0, 0 }, + { 118,4032, 0, 4, 1553, 53, 0, 0 }, + {4033,4033, 0, 0, 613, 60, 0, 0 }, + { 120,4034, 0, 4, 2126, 1166, 0, 0 }, + {4035,4036, 0, 1, 11880, 2993, 0, 0 }, + { 123,4037, 0, 4, 7080, 2473, 0, 0 }, + { 124,4038, 0, 4, 40000, 1126, 0, 0 }, + { 125,4039, 0, 4, 40000, 1546, 0, 0 }, + {4040,4040, 34, 0, 133, 40, 0, 0 }, + {4041,4041, 28, 0, 193, 46, 0, 0 }, + {4042,4043, 39, 1, 553, 126, 0, 0 }, + {4042,4043, 33, 1, 553, 126, 0, 0 }, + {4044,4045, 63, 4, 166, 93, 0, 0 }, + {4046,4046, 15, 0, 113, 66, 0, 0 }, + {4047,4047, 36, 0, 106, 53, 0, 0 }, + {4047,4048, 36, 1, 480, 173, 0, 0.40625 }, + {4049,4049, 35, 0, 706, 266, 0, 0 }, + {4050,4051, 38, 1, 273, 106, 0, 0 }, + {4052,4053, 38, 1, 366, 133, 0, 0 }, + {4054,4055, 48, 1, 280, 133, 0, -1.90625 }, + {4056,4056, 48, 0, 180, 86, 0, 0 }, + {4057,4058, 48, 1, 953, 346, 0, -1.90625 }, + {4059,4059, 61, 1, 3200, 540, 0, 0.09375 }, + {3369,1557, 70, 4, 766, 306, 0, 0 }, + {4060,4061, 79, 1, 1306, 513, 0, 0.078125 }, + {4062,4062, 62, 0, 5200, 466, 0, 0 }, + {4063,4064, 67, 1, 2153, 1080, 0, 0.078125 }, + {4065,4065, 62, 1, 3226, 573, 0, 0.09375 }, + {4066,4067, 54, 1, 286, 133, 0, 0 }, + {4066,4068, 48, 1, 286, 126, 0, 0 }, + {1589,1589, 71, 0, 106, 46, 0, 0 }, + { 389, 389, 42, 0, 266, 73, 0, 0 }, + {4069,4070, 60, 1, 120, 80, 0, 0 }, + {4070,4071, 60, 1, 380, 80, 0, 0 }, + {4072,4072, 73, 0, 166, 33, 0, 0 }, + {4073,4074, 68, 1, 153, 40, 0, 0 }, + {4075,4076, 18, 1, 200, 80, 0, 0 }, + {4077,4078, 18, 1, 253, 73, 0, 0 }, + {4079,4080, 64, 4, 1346, 33, 0, 0 }, + {4081,4082, 64, 1, 373, 73, 0, 0.03125 }, + {4083,4083, 67, 0, 106, 26, 0, 0 }, + { 844, 844,244, 2, 6, 0, 0, 0 }, + { 855, 855,244, 2, 6, 0, 0, 0 }, + { 880, 880,232, 0, 253, 80, 0, 0 }, + { 882, 882,220, 0, 40000, 266, 0, 0 }, + { 887, 887, 35, 0, 133, 46, 0, 0 }, + { 884, 884, 35, 0, 233, 80, 0, 0 }, + { 885, 885, 35, 0, 226, 86, 0, 0 }, + { 886, 886, 35, 0, 113, 53, 0, 0 }, + { 361, 361, 35, 0, 286, 73, 0, 0 }, + { 767, 767, 35, 0, 3020, 786, 0, 0 }, + { 888, 888, 35, 0, 246, 53, 0, 0 }, + {2141,2141, 35, 0, 186, 73, 0, 0 }, + { 891, 891, 35, 0, 713, 266, 0, 0 }, + {2142,2142, 35, 0, 200, 100, 0, 0 }, + {2143,2143, 35, 0, 220, 80, 0, 0 }, + {2144,2144, 35, 0, 2393, 100, 0, 0 }, + {2145,2145, 35, 0, 1980, 813, 0, 0 }, + { 376, 376, 35, 0, 1880, 840, 0, 0 }, + { 895, 895, 35, 0, 366, 140, 0, 0 }, + {2146,2146, 35, 0, 346, 106, 0, 0 }, + { 382, 382, 35, 0, 1073, 113, 0, 0 }, + {2147,2147, 35, 0, 106, 80, 0, 0 }, + { 898, 898, 35, 0, 206, 153, 0, 0 }, + { 899, 899, 35, 0, 633, 240, 0, 0 }, + { 900, 900, 35, 0, 620, 240, 0, 0 }, + { 871, 871, 35, 0, 380, 73, 0, 0 }, + { 388, 388, 35, 0, 286, 80, 0, 0 }, + { 901, 901, 35, 0, 260, 26, 0, 0 }, + { 902, 902, 35, 0, 1093, 73, 0, 0 }, + { 903, 903, 35, 0, 126, 73, 0, 0 }, + {3500,3500, 35, 2, 6, 0, 0, 0 }, + {4084,4084, 0, 0, 14166, 320, 0, 0 }, + {4085,4085, 0, 0, 7413, 653, 0, 0 }, + {4086,4086, 0, 0, 40000, 146, 0, 0 }, + {4087,4087, 0, 0, 40000, 113, 0, 0 }, + {4088,4088, 0, 0, 16773, 193, 0, 0 }, + {4089,4089, 0, 0, 40000, 73, 0, 0 }, + {4090,4090, 0, 0, 40000, 0, 0, 0 }, + {4091,4091, 0, 0, 966, 373, 0, 0 }, + {4092,4092, 0, 0, 40000, 80, 0, 0 }, + {4093,4093, 0, 0, 40000, 80, 0, 0 }, + {4094,4094, 0, 0, 18473, 93, 0, 0 }, + {4095,4095, 0, 0, 40000, 60, 0, 0 }, + {4096,4096, 0, 0, 40000, 73, 0, 0 }, + {4097,4097, 0, 0, 40000, 0, 0, 0 }, + {4098,4098, 0, 0, 40000, 213, 0, 0 }, + {4099,4099, 0, 0, 40000, 66, 0, 0 }, + {4100,4100, 0, 0, 1413, 1026, 0, 0 }, + {4101,4101, 0, 0, 506, 200, 0, 0 }, + {4102,4102, 0, 0, 3793, 1106, 0, 0 }, + {4103,4103, 0, 0, 40000, 220, 0, 0 }, + {4104,4104, 0, 0, 40000, 46, 0, 0 }, + {4105,4105, 0, 0, 40000, 0, 0, 0 }, + {4106,4106, 0, 0, 40000, 60, 0, 0 }, + {4107,4107, 0, 0, 40000, 0, 0, 0 }, + {4108,4108, 0, 0, 40000, 33, 0, 0 }, + {4109,4109, 0, 0, 40000, 0, 0, 0 }, + {4110,4110, 0, 0, 40000, 146, 0, 0 }, + {4111,4111, 0, 0, 40000, 66, 0, 0 }, + {4112,4112, 0, 0, 40000, 353, 0, 0 }, + {4113,4113, 0, 0, 40000, 66, 0, 0 }, + {4114,4114, 0, 0, 40000, 53, 0, 0 }, + {4115,4115, 0, 0, 40000, 73, 0, 0 }, + {4116,4116, 0, 0, 40000, 66, 0, 0 }, + {4117,4117, 0, 0, 40000, 926, 0, 0 }, + {4118,4118, 0, 0, 2833, 200, 0, 0 }, + { 127, 127, 36, 0, 386, 166, 0, 0 }, + {4119,4119, 36, 0, 100, 33, 0, 0 }, + {2030,2030, 36, 0, 346, 140, 0, 0 }, + {3782,3782, 48, 0, 93, 0, 0, 0 }, + {3783,3783, 36, 0, 146, 86, 0, 0 }, + {4120,4120, 48, 0, 1886, 653, 0, 0 }, + { 132, 132, 69, 0, 126, 66, 0, 0 }, + {4120,4120, 52, 0, 1853, 626, 0, 0 }, + { 152, 152, 48, 0, 220, 86, 0, 0 }, + {4120,4120, 55, 0, 1886, 640, 0, 0 }, + { 139, 139, 57, 0, 293, 133, 0, 0 }, + {4120,4120, 58, 0, 1860, 633, 0, 0 }, + {4120,4120, 60, 0, 1886, 633, 0, 0 }, + {4121,4121, 62, 0, 2660, 900, 0, 0 }, + {4120,4120, 63, 0, 1880, 646, 0, 0 }, + { 134, 134, 70, 0, 966, 360, 0, 0 }, + {4122,4122, 70, 0, 973, 346, 0, 0 }, + {4123,4123, 53, 0, 1866, 640, 0, 0 }, + {3516,3516, 48, 0, 180, 93, 0, 0 }, + {4124,4124, 84, 0, 1360, 473, 0, 0 }, + {4125,4125, 43, 0, 513, 206, 0, 0 }, + {4126,4126, 56, 0, 1353, 480, 0, 0 }, + {3791,3791, 24, 0, 1866, 613, 0, 0 }, + { 134, 134, 65, 0, 1346, 486, 0, 0 }, + { 146, 146, 48, 0, 173, 93, 0, 0 }, + { 146, 146, 54, 0, 173, 93, 0, 0 }, + {4127,4127, 42, 0, 246, 140, 0, 0 }, + {4127,4127, 39, 0, 240, 133, 0, 0 }, + {3816,3816, 52, 0, 306, 113, 0, 0 }, + {4128,4128, 52, 0, 413, 86, 0, 0 }, + { 158, 158, 60, 0, 146, 166, 0, 0 }, + { 158, 158, 66, 0, 146, 166, 0, 0 }, + { 158, 158, 59, 0, 146, 166, 0, 0 }, + {3538,3538, 91, 0, 773, 233, 0, 0 }, + {3547,3547,109, 0, 5300, 1786, 0, 0 }, + {4129,4129, 79, 0, 560, 313, 0, 0 }, + {4130,4130, 0, 0, 10646, 73, 0, 0 }, + {4131,4132, 0, 1, 14166, 586, 0, 0.03125 }, + {4133,4134, 0, 1, 15553, 546, 0, 0.03125 }, + {4135,4136, 0, 1, 11746, 320, 0, 0.046875 }, + {4137,4138, 0, 1, 14706, 646, 0, 0.15625 }, + {4139,4140, 0, 1, 7320, 100, 0, 0.046875 }, + {4141,4142, 0, 1, 40000, 0, 0, 0.0625 }, + {4143,4144, 0, 1, 13660, 260, 0, 0 }, + {4145,4146, 0, 1, 15026, 133, 0, 0 }, + {4147,4148, 0, 1, 40000, 0, 0, 2.5e-05 }, + {4149,4150, 0, 1, 4980, 3400, 0, 0 }, + {4151,4152, 0, 1, 7840, 2660, 0, 0.046875 }, + {4153,4154, 0, 1, 8326, 180, 0, 0 }, + {4155,4156, 0, 1, 1093, 140, 0, 0 }, + {4157,4158, 0, 1, 2280, 400, 0, 0 }, + {4159,4160, 0, 1, 4553, 1486, 0, 0.03125 }, + {4161,4161, 0, 1, 40000, 0, 0, 0.03125 }, + {4162,4163, 0, 1, 40000, 60, 0, 0.15625 }, + {4164,4165, 0, 1, 40000, 93, 0, 0.078125 }, + {4166,4167, 0, 1, 40000, 86, 0, 0.15625 }, + {4168,4169, 0, 1, 40000, 520, 0, 0.03125 }, + {4170,4171, 0, 1, 40000, 140, 0, 0.0625 }, + {4172,4173, 0, 1, 40000, 133, 0, 0.140625 }, + {4174,4175, 0, 1, 40000, 73, 0, 0 }, + {4176,4177, 0, 1, 40000, 346, 0, 0.109375 }, + {4178,4179, 0, 1, 3693, 86, 0, 0 }, + {4180,4181, 0, 1, 6586, 460, 0, 2.5e-05 }, + {4182,4183, 0, 1, 4320, 93, 0, 0 }, + {4184,4185, 0, 1, 7346, 126, 0, 0.046875 }, + {4186,4187, 0, 1, 3633, 260, 0, 0 }, + {4188,4189, 0, 1, 40000, 126, 0, -1.95312 }, + {4190,4191, 0, 1, 40000, 126, 0, -1.9375 }, + {4192,4193, 0, 1, 40000, 46, 0, 0.234375 }, + {4194,4195, 0, 1, 40000, 0, 0, 0.03125 }, + {4196,4197, 0, 1, 10320, 86, 0, 0 }, + {4198,4199, 0, 1, 12933, 133, 0, 0 }, + {4200,4201, 0, 1, 11820, 240, 0, 0.046875 }, + {4202,4203, 0, 1, 3966, 166, 0, 0 }, + {4204,4205, 0, 1, 40000, 0, 0, 0 }, + {4206,4206, 0, 0, 2666, 160, 0, 0 }, + {4207,4208, 0, 1, 15046, 93, 0, 0.078125 }, + {4209,4210, 0, 1, 40000, 100, 0, 0 }, + {4211,4211, 0, 0, 40000, 260, 0, 0 }, + {4212,4213, 0, 1, 40000, 126, 0, 2.5e-05 }, + {4214,4214, 0, 0, 40000, 233, 0, 0 }, + {4215,4216, 0, 1, 40000, 440, 0, 0.078125 }, + {4217,4218, 0, 1, 2160, 606, 0, 0.109375 }, + {4219,4220, 0, 1, 14753, 2400, 0, 0.03125 }, + {4221,4222, 0, 1, 7680, 646, 0, 0.03125 }, + {4223,4224, 0, 1, 40000, 446, 0, 0.0625 }, + {4225,4226, 0, 1, 40000, 866, 0, -0.0625 }, + {4227,4227, 0, 1, 40000, 1220, 0, 0.078125 }, + {4228,4228, 0, 1, 40000, 1960, 0, 0.0625 }, + {4229,4230, 0, 1, 40000, 433, 0, 0.125 }, + {4231,4232, 0, 1, 40000, 140, 0, 0.140625 }, + {4233,4234, 0, 1, 40000, 806, 0, 0.109375 }, + {4235,4236, 0, 1, 2040, 486, 0, 0.125 }, + {4237,4238, 0, 1, 40000, 86, 0, 0 }, + {4239,4240, 0, 1, 40000, 80, 0, 0.03125 }, + {4241,4241, 0, 0, 40000, 73, 0, 0 }, + {4242,4243, 0, 1, 40000, 400, 0, 0.0625 }, + {4244,4245, 0, 1, 40000, 120, 0, 0.0625 }, + {4246,4247, 0, 1, 40000, 0, 0, 0.09375 }, + {4248,4248, 0, 1, 40000, 0, 0, 0.125 }, + {4249,4250, 0, 1, 40000, 186, 0, 0 }, + {4251,4251, 0, 0, 40000, 166, 0, 0 }, + {4252,4252, 0, 0, 40000, 73, 0, 0 }, + {4253,4253, 0, 0, 40000, 60, 0, 0 }, + {4254,4255, 0, 1, 40000, 140, 0, 0 }, + {4256,4256, 0, 0, 40000, 140, 0, 0 }, + {4257,4257, 0, 0, 40000, 66, 0, 0 }, + {4258,4259, 0, 1, 40000, 133, 0, 0 }, + {4260,4260, 0, 0, 40000, 86, 0, 0 }, + {4261,4261, 0, 0, 40000, 73, 0, 0 }, + {4262,4262, 0, 0, 40000, 106, 0, 0 }, + {4263,4264, 0, 1, 40000, 186, 0, 0.03125 }, + {4265,4266, 0, 1, 40000, 0, 0, 0.03125 }, + {4267,4267, 0, 0, 40000, 300, 0, 0 }, + {4268,4268, 0, 0, 40000, 66, 0, 0 }, + {4269,4270, 0, 1, 40000, 73, 0, 0.125 }, + {4271,4272, 0, 1, 40000, 86, 0, 0.109375 }, + {4273,4274, 0, 1, 40000, 146, 0, 0.109375 }, + {4275,4276, 0, 1, 40000, 66, 0, -0.03125 }, + {4277,4277, 0, 0, 40000, 60, 0, 0 }, + {4278,4279, 0, 1, 40000, 213, 0, 0.15625 }, + {4280,4281, 0, 1, 40000, 66, 0, 0.125 }, + {4282,4283, 0, 1, 40000, 100, 0, 0.03125 }, + {4284,4285, 0, 1, 40000, 1513, 0, 0.078125 }, + {4286,4287, 0, 1, 40000, 353, 0, 0.109375 }, + {4288,4289, 0, 1, 40000, 133, 0, 0.078125 }, + {4290,4291, 0, 1, 40000, 746, 0, 0.140625 }, + {4292,4293, 0, 1, 40000, 0, 0, 0.109375 }, + {4294,4295, 0, 1, 5033, 1606, 0, 0.0625 }, + {4296,4297, 0, 1, 40000, 1146, 0, 0.09375 }, + {4298,4299, 0, 1, 40000, 1586, 0, 0.109375 }, + {4300,4301, 0, 1, 40000, 0, 0, 0.09375 }, + {4302,4303, 0, 1, 40000, 1006, 0, 0.125 }, + {4304,4304, 0, 1, 2680, 793, 0, 0.109375 }, + {4305,4306, 0, 1, 40000, 0, 0, -0.046875 }, + {4307,4308, 0, 1, 9000, 3186, 0, 0.125 }, + {4309,4310, 0, 1, 40000, 1073, 0, -0.078125 }, + {4311,4312, 0, 1, 40000, 2093, 0, 0.140625 }, + {4313,4314, 0, 1, 40000, 0, 0, 0.078125 }, + {4315,4316, 0, 1, 9580, 713, 0, 0.03125 }, + {4317,4317, 0, 0, 1166, 760, 0, 0 }, + {4318,4319, 0, 1, 1186, 240, 0, 0 }, + {4320,4320, 0, 0, 40000, 160, 0, 0 }, + {4321,4321, 0, 0, 40000, 120, 0, 0 }, + {4322,4322, 0, 0, 8673, 2413, 0, 0 }, + {4323,4323, 0, 0, 393, 126, 0, 0 }, + {4324,4324, 0, 0, 246, 93, 0, 0 }, + {4325,4326, 0, 1, 1953, 393, 0, 0 }, + {4327,4328, 0, 1, 4220, 133, 0, 0 }, + {4329,4330, 0, 1, 2873, 73, 0, 0.109375 }, + {4331,4332, 0, 1, 40000, 186, 0, 0 }, + {4333,4333, 0, 0, 1573, 86, 0, 0 }, + {4334,4335, 0, 1, 40000, 793, 0, 0 }, + {4336,4337, 0, 1, 40000, 173, 0, 0 }, + {4338,4339, 0, 1, 40000, 793, 0, 0 }, + {4340,4340, 0, 0, 606, 133, 0, 0 }, + {4044,4341, 63, 1, 160, 80, 0, 0 }, + {4342,4343, 25, 1, 313, 153, 0, 0 }, + {4344,4343, 25, 1, 206, 100, 0, 0 }, + {4345,4346, 61, 1, 153, 93, 0, 0 }, + {4347,4348, 38, 1, 340, 133, 0, 0 }, + {4349,4350, 37, 1, 206, 93, 0, 0 }, + {4351,4352, 15, 1, 346, 153, 10, 0 }, + {4353,4354,100, 1, 146, 80, 0, 0.140625 }, + {4355,4356, 19, 1, 553, 200, 10, 0 }, + {4357,4358, 15, 1, 333, 153, 20, 0 }, + {4359,4360, 12, 1, 340, 146, 20, 0 }, + {4361,4362, 11, 1, 346, 146, 20, 0 }, + {4363,4364, 61, 1, 2706, 1033, 0, 0.09375 }, + {4365,4362, 8, 1, 340, 146, 20, 0 }, + {4366,4367, 91, 1, 1166, 366, 0, -0.046875 }, + {4368,4368, 70, 0, 966, 346, 0, 0 }, + {4369,4370, 80, 1, 300, 93, 0, 0.125 }, + {4371,4371, 58, 0, 206, 53, 0, 0 }, + {4372,4364, 62, 1, 2333, 820, 0, 0.09375 }, + {4373,4374, 31, 1, 773, 200, 0, 0 }, + {4375,4367, 91, 1, 1160, 360, 0, -0.03125 }, + {4376,4377, 41, 1, 373, 113, 0, 0 }, + {4378,4379, 35, 1, 406, 126, 0, 0 }, + {4380,4381, 29, 1, 146, 106, 0, 0 }, + {4382,4383, 41, 1, 400, 126, 0, 0 }, + {4382,4383, 37, 1, 400, 126, 0, 0 }, + {4384,4385, 77, 1, 193, 93, 0, 0 }, + {4386,4387, 72, 1, 200, 93, 0, 0 }, + {4388,4388, 40, 0, 513, 0, 0, 0 }, + {4389,4389, 38, 0, 200, 20, 0, 0 }, + {4390,4390, 36, 0, 620, 20, 0, 0 }, + {4391,4391, 90, 0, 193, 20, 0, 0 }, + {4392,4392, 90, 0, 793, 40, 0, 0 }, + {4393,4394, 80, 1, 406, 153, 0, 0.03125 }, + {4395,4396, 64, 1, 1866, 606, 0, 0 }, + {4397,4398, 50, 1, 173, 126, 0, 0 }, + {4399,4399, 36, 0, 4646, 1606, 0, 0 }, + {4400,4400, 0, 0, 40000, 86, 0, 0 }, + {4401,4401, 0, 0, 40000, 73, 0, 0 }, + {4402,4402, 0, 0, 2433, 700, 0, 0 }, + {4403,4403, 0, 0, 1233, 26, 0, 0 }, + {4404,4404, 0, 0, 40000, 66, 0, 0 }, + {4405,4405, 0, 0, 40000, 60, 0, 0 }, + {4406,4406, 0, 0, 40000, 60, 0, 0 }, + {4407,4407, 0, 0, 40000, 66, 0, 0 }, + {4408,4408, 0, 0, 40000, 66, 0, 0 }, + {4409,4409, 0, 0, 40000, 0, 0, 0 }, + {4409,4409, 73, 0, 40000, 0, 0, 0 }, + {4410,4410, 0, 0, 40000, 60, 0, 0 }, + {4411,4411, 0, 0, 40000, 60, 0, 0 }, + {4412,4412, 0, 0, 7326, 2486, 0, 0 }, + {4413,4413, 0, 0, 4886, 1586, 0, 0 }, + {4414,4414, 0, 0, 646, 20, 0, 0 }, + {4415,4415, 0, 0, 253, 20, 0, 0 }, + {4415,4415, 12, 0, 253, 20, 0, 0 }, + {4416,4416, 0, 0, 640, 100, 0, 0 }, + {4416,4416, 1, 0, 640, 106, 0, 0 }, + {4417,4417, 0, 0, 133, 106, 0, 0 }, + {4417,4417, 23, 0, 133, 106, 0, 0 }, + {4418,4418, 0, 0, 653, 100, 0, 0 }, + {4419,4419, 0, 0, 4166, 1546, 0, 0 }, + {4420,4420, 0, 0, 40000, 73, 0, 0 }, + {4421,4421, 0, 0, 40000, 60, 0, 0 }, + {4422,4422, 0, 0, 40000, 53, 0, 0 }, + {4423,4423, 0, 0, 40000, 0, 0, 0 }, + {4424,4424, 0, 0, 246, 20, 0, 0 }, + {4425,4425, 0, 2, 6, 0, 0, 0 }, + {4426,4426, 0, 0, 4946, 233, 0, 0 }, + {4427,4427, 0, 0, 4946, 233, 0, 0 }, + {4428,4428, 0, 0, 4953, 240, 0, 0 }, + {4429,4429, 0, 0, 4946, 233, 0, 0 }, + {4430,4430, 0, 0, 18233, 46, 0, 0 }, + {4431,4431, 0, 0, 2386, 26, 0, 0 }, + {4432,4432, 0, 0, 4640, 633, 0, 0 }, + {4433,4433, 0, 0, 18466, 100, 0, 0 }, + {4434,4434, 0, 0, 18440, 66, 0, -2 }, + {4435,4435, 0, 0, 18440, 6140, 0, -2 }, + {4436,4436, 0, 0, 1206, 433, 0, -2 }, + {4437,4437, 0, 0, 4626, 240, 0, 0 }, + {4438,4438, 0, 0, 726, 400, 0, 0 }, + {4439,4439, 0, 0, 5866, 73, 0, 0 }, + {4440,4440, 0, 0, 40000, 73, 0, 0 }, + {4441,4441, 0, 0, 40000, 73, 0, 0 }, + {4442,4442, 0, 0, 40000, 73, 0, 0 }, + {4443,4443, 0, 0, 40000, 73, 0, 0 }, + {4444,4444, 0, 0, 6500, 346, 0, 0 }, + {4445,4445, 0, 0, 6506, 346, 0, 0 }, + {4446,4446, 0, 0, 40000, 66, 0, -2 }, + {4447,4447, 0, 0, 40000, 66, 0, -2 }, + {4448,4448, 0, 0, 40000, 0, 0, 0 }, + {4449,4449, 0, 0, 40000, 46, 0, 0 }, + {4450,4450, 0, 0, 40000, 0, 0, 0 }, + {4450,4450, 0, 0, 40000, 0, 0, -2 }, + {4451,4451, 0, 0, 2386, 26, 0, 0 }, + {4452,4452, 0, 0, 40000, 73, 0, -2 }, + {4453,4453, 0, 0, 5866, 26, 0, -2 }, + {4454,4454, 0, 0, 40000, 133, 0, 0 }, + {4455,4455, 0, 0, 40000, 133, 0, 0 }, + {4456,4456, 0, 0, 40000, 126, 0, 0 }, + {4457,4457, 0, 0, 253, 20, 0, 0 }, + {4458,4458, 0, 0, 8866, 1366, 0, 0 }, + {4459,4459, 0, 0, 1040, 766, 0, 0 }, + {4460,4460, 0, 0, 40000, 146, 0, -2 }, + {4461,4461, 0, 0, 40000, 153, 0, -2 }, + {4462,4462, 0, 0, 40000, 466, 0, -2 }, + {4463,4463, 0, 0, 40000, 66, 0, 0 }, + {4464,4464, 0, 0, 2333, 566, 0, 0 }, + {4465,4465, 0, 0, 40000, 140, 0, -2 }, + {4466,4466, 0, 0, 40000, 100, 0, -2 }, + {4467,4467, 0, 0, 40000, 226, 0, -2 }, + {4468,4468, 0, 0, 40000, 0, 0, 0 }, + {3712,3712, 0, 0, 40000, 226, 0, -2 }, + {4469,4469, 0, 0, 40000, 140, 0, -2 }, + {4470,4470, 0, 0, 40000, 66, 0, 0 }, + {4471,4471, 0, 0, 40000, 73, 0, 0 }, + {4472,4472, 0, 0, 40000, 73, 0, 0 }, + {4473,4473, 0, 0, 40000, 86, 0, -2 }, + {4474,4474, 0, 0, 40000, 80, 0, 0 }, + {4475,4475, 0, 0, 40000, 73, 0, -2 }, + {4476,4476, 0, 0, 40000, 80, 0, -2 }, + {4477,4477, 0, 0, 40000, 73, 0, -2 }, + {4478,4478, 0, 0, 40000, 73, 0, 0 }, + {4479,4479, 0, 0, 40000, 73, 0, 0 }, + {4480,4480, 0, 0, 40000, 93, 0, 0 }, + {4481,4481, 0, 0, 40000, 73, 0, 0 }, + {4482,4482, 0, 0, 11946, 13, 0, 0 }, + {4483,4483, 0, 0, 40000, 73, 0, 0 }, + {4453,4453, 0, 0, 5866, 26, 0, 0 }, + {4484,4484, 0, 0, 40000, 820, 0, 0 }, + {4485,4485, 0, 0, 2153, 873, 0, 0 }, + {1221,1221, 0, 0, 40000, 293, 0, 0.171875 }, + {4486,4486, 0, 0, 1620, 120, 0, 0 }, + {4487,4487, 0, 0, 15120, 93, 0, 0 }, + {4488,4488, 0, 0, 14613, 93, 0, 0 }, + {4489,4489, 0, 0, 2346, 793, 0, 0 }, + {4490,4490, 0, 0, 40000, 2380, 0, 0 }, + {4491,4491, 0, 0, 40000, 1280, 0, 0 }, + {4492,4492, 0, 0, 40000, 1460, 0, 0 }, + {4493,4493, 0, 0, 40000, 2513, 0, 0 }, + {4494,4494, 0, 0, 14840, 1266, 0, 0 }, + {4495,4495, 0, 0, 4513, 640, 0, 0 }, + {4496,4496, 0, 0, 4680, 806, 0, 0 }, + {4497,4497, 0, 0, 40000, 100, 0, 0 }, + {4498,4498, 0, 0, 40000, 66, 0, 0 }, + {4499,4499, 0, 0, 2420, 413, 0, 0 }, + {4500,4500, 0, 0, 406, 73, 0, -2 }, + {4501,4501, 0, 0, 1166, 400, 0, 0 }, + {4502,4502, 0, 0, 1213, 106, 0, 0 }, + {4503,4503, 0, 0, 273, 60, 0, -2 }, + {4504,4504, 0, 0, 40000, 2380, 0, 0 }, + {4505,4505, 0, 0, 40000, 440, 0, 0 }, + {1261,1261, 0, 0, 40000, 2960, 0, 0 }, + {4506,4506, 37, 0, 973, 73, 0, -2 }, + {4507,4507, 48, 0, 106, 26, 0, -2 }, + {4508,4508, 48, 0, 286, 133, 0, -2 }, + {4509,4509, 62, 0, 166, 60, 0, 0 }, + {4510,4510, 44, 0, 980, 360, 0, 0 }, + {4511,4511, 80, 0, 100, 33, 0, 0 }, + {4510,4510, 50, 0, 980, 346, 0, 0 }, + {4512,4512, 48, 0, 106, 46, 0, -2 }, + {4510,4510, 55, 0, 973, 360, 0, 0 }, + {4513,4513, 61, 0, 513, 20, 0, 0 }, + {4510,4510, 58, 0, 966, 353, 0, 0 }, + {4510,4510, 63, 0, 973, 353, 0, 0 }, + {4514,4514, 71, 0, 1366, 580, 0, 0 }, + {4510,4510, 72, 0, 820, 306, 0, 0 }, + {4515,4515, 70, 0, 1886, 666, 0, 0 }, + {4514,4514, 88, 0, 1353, 560, 0, 0 }, + {4516,4516, 76, 0, 1873, 653, 0, 0 }, + {4517,4517, 84, 0, 260, 113, 0, 0 }, + {4514,4514, 68, 0, 1366, 553, 0, 0 }, + {4518,4518, 72, 0, 153, 53, 0, 0 }, + {4519,4519, 28, 0, 1193, 413, 0, 0 }, + {4515,4515, 81, 0, 1353, 480, 0, 0 }, + {4520,4520, 58, 0, 246, 120, 0, -2 }, + {4520,4520, 55, 0, 246, 120, 0, -2 }, + {4520,4520, 44, 0, 246, 120, 0, -2 }, + {4520,4520, 49, 0, 246, 120, 0, -2 }, + {4520,4520, 40, 0, 286, 133, 0, -2 }, + {4521,4521, 55, 0, 740, 560, 0, -2 }, + {4521,4521, 48, 0, 893, 693, 0, -2 }, + {4522,4522, 52, 0, 513, 206, 0, 0 }, + {4522,4522, 45, 0, 513, 206, 0, 0 }, + {4523,4523, 48, 0, 173, 100, 0, -2 }, + {4524,4524, 48, 0, 120, 266, 0, -2 }, + {4525,4525, 48, 0, 253, 60, 0, -2 }, + {4500,4500, 73, 0, 160, 20, 0, -2 }, + {4500,4500, 68, 0, 160, 20, 0, -2 }, + {4500,4500, 63, 0, 193, 20, 0, -2 }, + {4526,4526,108, 0, 406, 26, 0, 0 }, + {4527,4527,108, 0, 740, 26, 0, 0 }, }; //Returns total number of generated banks int maxAdlBanks() -{ return 75; +{ + return 75; } -const char* const banknames[75] = +const char* const banknames[76] = { "AIL (Star Control 3, Albion, Empire 2, etc.)", "Bisqwit (selection of 4op and 2op)", @@ -9437,8 +9303,8 @@ const char* const banknames[75] = "TMB (Shadow Warrior)", "DMX (Raptor)", "OP3 (Modded GMOPL by Wohlstand)", - "SB (Jammey O'Connel's bank)", - "TMB (Default bank of Apgee Sound System)", + "SB (Jamie O'Connell's bank)", + "TMB (Default bank of Apogee Sound System)", "WOPL (4op bank by James Alan Nguyen and Wohlstand)", "TMB (Blood)", "TMB (Lee)", @@ -9446,6 +9312,7 @@ const char* const banknames[75] = "WOPL (DMXOPL3 bank by Sneakernets)", "EA (Cartooners)", "WOPL (Apogee IMF 90-ish)", + NULL }; const unsigned short banks[75][256] = { @@ -10404,68 +10271,68 @@ const unsigned short banks[75][256] = 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3098,3205,3101,3129,3130,3131,3108,3132,3209,3210,3120,3133,3124,3134,3103,3135, -3136,3137,3113,3138,3139,3140,3141,3142,3143,3144,3145,3206,3121,3207,3208,3146, -3127,3147,3148,3211,3212,3149,3150,3151,3116,3106,3152,3110,3111,3213,3104,3126, -3105,3117,3153,3154,3102,3214,3155,3119,3215,3216,3115,3109,3217,3114,3112,3218, -3156,3219,3157,3158,3159,3107,3122,3128,3160,3222,3161,3162,3163,3164,3165,3166, -3167,3168,3169,3170,3171,3172,3173,3174,3223,3175,3176,3177,3118,3221,3220,3178, -3226,3241,3179,3180,3242,3181,3182,3183,3184,3185,3186,3187,3125,3188,3189,3190, -3191,3192,3193,3194,3123,3195,3196,3197,3198,3224,3199,3200,3201,3202,3203,3204, +1551,1552,1553,3101, 181, 182, 183,3102, 185,1556,1557,3103,1559, 188, 189,1560, +1561,1562, 193,1564,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, + 206, 207, 208,1568,1569,1570,1571, 211,1572,1573, 214, 215, 216, 217, 218, 219, + 220, 221,1574,1575,1576,1577,1578, 225,1579,1580,3100,1581,1582, 229, 230, 231, + 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,1586, 242, 243, 244,1587, + 246, 247,1588,1589, 249, 250, 251,1590, 252, 253, 254, 255,1591,1592,1593,1594, +1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, +1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,3104,3105, 295, 284, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127,3227,3244,3248,3268,3245,3243,3246,3227,3247,3227,3249,3227, -3227,3269,3227,3228,3270,3229,3250,3251,3100,3271,3258,3230,3252,3253,3237,3239, -3259,3254,3255,3256,3260,3235,3261,3257,3099,3265,3266,3232,3233,3233,3267,3262, -3263,3264,3236,3225,3231,3234,3238,3240, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295, 127,3107,3122,3126, 316,3123,3121,3124,3107,3125,3107,3127,3107, +3107, 329,3107,3108,3143,3109,3128,3129,3099,3144,1634,3110,3130,3131,3117,3119, +3136,3132,3133,3134,3137,3115,3138,3135,3098, 343, 344,3112,3113,3113,3142,3139, +3140,3141,3116,3106,3111,3114,3118,3120, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3098,3205,3101,3129,3130,3131,3108,3132,3209,3210,3120,3133,3124,3134,3103,3135, -3136,3137,3113,3138,3139,3140,3141,3142,3143,3144,3145,3206,3121,3207,3208,3146, -3127,3147,3148,3211,3212,3149,3150,3151,3116,3106,3152,3110,3111,3213,3104,3126, -3105,3117,3153,3154,3102,3214,3155,3119,3215,3216,3115,3109,3217,3114,3112,3218, -3156,3219,3157,3158,3159,3107,3122,3128,3160,3222,3161,3162,3163,3164,3165,3166, -3167,3168,3169,3170,3171,3172,3173,3174,3223,3175,3176,3177,3118,3221,3220,3178, -3226,3241,3179,3180,3242,3181,3182,3183,3184,3185,3186,3187,3125,3188,3189,3190, -3191,3192,3193,3194,3123,3195,3196,3197,3198,3224,3199,3200,3201,3202,3203,3204, +1551,1552,1553,3101, 181, 182, 183,3102, 185,1556,1557,3103,1559, 188, 189,1560, +1561,1562, 193,1564,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, + 206, 207, 208,1568,1569,1570,1571, 211,1572,1573, 214, 215, 216, 217, 218, 219, + 220, 221,1574,1575,1576,1577,1578, 225,1579,1580,3100,1581,1582, 229, 230, 231, + 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,1586, 242, 243, 244,1587, + 246, 247,1588,1589, 249, 250, 251,1590, 252, 253, 254, 255,1591,1592,1593,1594, +1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, +1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,3104,3105, 295, 284, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3274,3274,3277,3275,3276,3275,3272,3272,3272,3272,3272,3272,3272, -3272,3272,3272,3272,3272,3272,3278,3279,3301,3269,3280,3269,3281,3282,3283,3284, -3285,3286,3287,3288,3289, 349,3290,3291,3292,3293,3294,3276,3276,3276,3295,3296, -3297,3298, 349,3299,3300,3276,3283,3284,3273, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295,2430,2430,3149,3147,3148,3147,3145,3145,3145,3145,3145,3145,3145, +3145,3145,3145,3145,3145,3145,3150,3151,3173, 329,3152, 329,3153,3154,3155,3156, +3157,3158,3159,3160,3161, 349,3162,3163,3164,3165,3166,3148,3148,3148,3167,3168, +3169,3170, 349,3171,3172,3148,3155,3156, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317, -3318,3319,3320,3321,3322,3323,3324,3324,3325,3326,3327,3328,3329,3330,3331,3332, -3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,3344,3345,3346,3347,3348, -3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3324,3360,3361,3362,3363, -3324,3364,3365,3366,3324,3367,3324,3368,3324,3369,3324,3370,3324,3371,3372,3373, -3374,3375,3376,3324,3377,3378,3324,3379,3380,3381,3382,3383,3324,3324,3384,3324, -3385,3324,3386,3324,3387,3388,3324,3389,3324,3324,3390,3324,3324,3324,3324,3324, -3324,3324,3324,3391,3324,3324,3324,3324,3324,3324,3392,3393,3324,3324,3324,3324, -3394,3395, 285,3396,3397, 287, 288,3398,3399,3399,3399,3399,3399,3399,3399,3399, -3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399, -3399,3399,3399,3400,3401,3399,3402,3399,3403,3404,3405,3406,3407,3408,3409,3410, -3410,3411,3408,3412,3399,3399,3413,3414,3399,3399,3399,3399,3399,3399,3399,3399, -3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399, -3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399, -3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399, -3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399,3399, +3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189, +3190,3191,3192,3193,3194,3195,3196,3196,3197,3198,3199,3200,3201,3202,3203,3204, +3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220, +3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3196,3232,3233,3234,3235, +3196,3236,3237,3238,3196,3239,3196,3240,3196,3241,3196,3242,3196,3243,3244,3245, +3246,3247,3248,3196,3249,3250,3196,3251,3252,3253,3254,3255,3196,3196,3256,3196, +3257,3196,3258,3196,3259,3260,3196,3261,3196,3196,3262,3196,3196,3196,3196,3196, +3196,3196,3196,3263,3196,3196,3196,3196,3196,3196,3264,3265,3196,3196,3196,3196, +3266,3267, 285,3268,3269, 287, 288,3270,3271,3271,3271,3271,3271,3271,3271,3271, +3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, +3271,3271,3271,3272,3273,3271,3274,3271,3275,3276,3277,3278,3279,3280,3281,3282, +3282,3283,3280,3284,3271,3271,3285,3286,3271,3271,3271,3271,3271,3271,3271,3271, +3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, +3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, +3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, +3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, }, { -3415,3416, 466,3417, 713,3324,3418, 467,3419, 632,3420,3421,3422,3423,3424,3425, -3426, 598,3427,3428,3429,3430,3431,3432,1512,3433,3422,3434, 759, 437, 437,3435, -3436,3437, 439,3438, 440,3439, 442, 441,3440,3441,3442,3443,2306,3444,3445, 582, -3446,3447, 452,3448,3449,3418,3450,3451,3452, 778,3453,2312, 779,3454,3455,3456, -3457, 769,3458,3459,3460,3461, 663, 664,3462,2316,3463,3464,3465,1299,3466,3467, -3468,3469,3470,3471,3472,3473,3474, 442,3475,3476,3477,3432,3478,1669,3479,3480, -3481,3482,3483,3484,3481, 261,3485,3486,1919,2420,3487,3488, 676,3489,3490,3491, -3492,3493,3494,3495, 677,3496, 677,3497,3498, 677,3499, 455,3500,2421,3501, 465, +3287,3288, 466,3289, 713,3196,3290, 467,3291, 632,3292,3293,3294,3295,3296,3297, +3298, 598,3299,3300,3301,3302,3303,3304,1512,3305,3294,3306, 759, 437, 437,3307, +3308,3309, 439,3310, 440,3311, 442, 441,3312,3313,3314,3315,2306,3316,3317, 582, +3318,3319, 452,3320,3321,3290,3322,3323,3324, 778,3325,2312, 779,3326,3327,3328, +3329, 769,3330,3331,3332,3333, 663, 664,3334,2316,3335,3336,3337,1299,3338,3339, +3340,3341,3342,3343,3344,3345,3346, 442,3347,3348,3349,3304,3350,1669,3351,3352, +3353,3354,3355,3356,3353, 261,3357,3358,1919,2420,3359,3360, 676,3361,3362,3363, +3364,3365,3366,3367, 677,3368, 677,3369,3370, 677,3371, 455,3372,2421,3373, 465, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, @@ -10476,14 +10343,14 @@ const unsigned short banks[75][256] = 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3502,3502,3503,3504,3505,3506,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515, -3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531, -3532,3533,3534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547, -3548,3549,3550,3551,3552,3553,3554,3555,3553,3556,3557,3558,3559,3560,3561,3562, -3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3463,3575,3576,3577, -3578,3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3590,3591,3592, -3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608, -3609,3610,3609,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623, +3374,3374,3375,3376,3377,3378,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387, +3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403, +3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419, +3420,3421,3422,3423,3424,3425,3426,3427,3425,3428,3429,3430,3431,3432,3433,3434, +3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3335,3447,3448,3449, +3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3462,3463,3464, +3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480, +3481,3482,3481,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,3494,3495, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, @@ -10505,114 +10372,114 @@ const unsigned short banks[75][256] = 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,3624, 150, 151, 152, 153, 154, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,3496, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -1551,1552,1553,1554, 181, 182, 183,1555, 185,1556,3625,3626,3627, 188, 189,1560, -1561,1562,1563,3628,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, - 206, 207, 208,1568,1569,1570,1571,3629,1572,1573, 214, 215, 216, 217, 218, 219, +1551,1552,1553,1554, 181, 182, 183,1555, 185,1556,3497,3498,3499, 188, 189,1560, +1561,1562,1563,3500,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, + 206, 207, 208,1568,1569,1570,1571,3501,1572,1573, 214, 215, 216, 217, 218, 219, 220, 221,1574,1575,1576,1577,1578, 225,1579,1580, 226,1581,1582, 229, 230, 231, 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,1586, 242, 243, 244,1587, 246, 247,1588,1589, 249, 250, 251,1590, 252, 253, 254, 255,1591,1592,1593,1594, 1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, -1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,3630,3631, 295, 284, +1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,3502,3503, 295, 284, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127,3632,1613,1614,3633,1616,3634,1618,3635,1620,3636,1622,3637, -3638,1625,3639,3640,1628,1629,1630,1631,3641,1633,1634,3642,1636,1637,1638,1639, + 295, 295, 295, 127,3504,1613,1614,3505,1616,3506,1618,3507,1620,3508,1622,3509, +3510,1625,3511,3512,1628,1629,1630,1631,3513,1633,1634,3514,1636,1637,1638,1639, 1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655, 1656,1657,1658,1659,1660,1661,1662,1663, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658, -3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674, -3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690, -3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706, -3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,3719,3720,3721,3722, -3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738, -3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,3749,3750,3751,3752,3753,3754, -3755,3756,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770, +3515,3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530, +3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546, +3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562, +3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578, +3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594, +3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610, +3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626, +3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784, -3785,3786,3787,3788,3786,3789,3790,3786,3791,3786,3792,3793,3794,3795,3796,3797, -3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813, -3814,3815, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656, +3657,3658,3659,3660,3658,3661,3662,3658,3663,3658,3664,3665,3666,3667,3668,3669, +3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685, +3686,3687, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3415,1492,3816,3417, 713,3817,3818, 730,1914,3819,1533,3421,3820,3821,3822,3823, -3426,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834, 759, 437,3835,3836, -3436,3837,3838,3839,3840,3841, 442,3842,3843,3844,3845,3846,3847,3848,3849,3850, -3851,2306,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865, -3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881, -3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897, -3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913, -3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3499,3924,3925,2421,3926,3927, +3287,1492,3688,3289, 713,3689,3690, 730,1914,3691,1533,3293,3692,3693,3694,3695, +3298,3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706, 759, 437,3707,3708, +3308,3709,3710,3711,3712,3713, 442,3714,3715,3716,3717,3718,3719,3720,3721,3722, +3723,2306,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737, +3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,3749,3750,3751,3752,3753, +3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769, +3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785, +3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3371,3796,3797,2421,3798,3799, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784, -3785,3786,3787,3788,3786,3789,3790,3786,3791,3786,3792,3793,3794,3795,3796,3797, -3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813, -3814,3815, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656, +3657,3658,3659,3660,3658,3661,3662,3658,3663,3658,3664,3665,3666,3667,3668,3669, +3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685, +3686,3687, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943, -3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959, -3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975, -3968,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990, -3991,3992,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005, -4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021, -4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037, -4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053, +3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815, +3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831, +3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847, +3840,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862, +3863,3864,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877, +3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893, +3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909, +3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067, -4068,4069,4070,3788,4071,4072,3790,4073,3791,4074,4075,3793,4076,4077,4078,4079, -4080,4081,4082,4083,4084,4064,3804,4085,4086,3807,4087,4088,4089,4090,3812,3813, -4091,4092,4093, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939, +3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955, +3956,3957,3958,3959,3960,3936,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970, +3971,3972,3973, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943, -3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3958,4094,3959, -3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,4095,3973,3974,3975, -3968,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,4096,3990, -3991,3992,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005, -4097,4007,4098,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021, -4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4099,4100,4101,4035,4036,4037, -4038,4039,4040,4041,4102,4043,4044,4103,4046,4047,4048,4049,4050,4051,4052,4053, -4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104, -4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4105,4105,4105,4105,4106, -4105,4105,4105,4055,4056,4107,4058,4059,4060,4108,4062,4063,4064,4065,4066,4067, -4068,4069,4070,3788,4071,4072,3790,4073,3791,4074,4075,3793,4076,4077,4078,4079, -4080,4081,4082,4083,4084,4064,3804,4085,4086,4109,4110,4088,4111,4112,3812,3813, -4091,4092,4093,4105,4105,4105,4105,4105,4105,4104,4113,4113,4113,4113,4113,4113, -4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113, -4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113, +3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815, +3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3974,3975,3831, +3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3976,3845,3846,3847, +3840,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3977,3860,3978,3862, +3863,3864,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877, +3979,3879,3980,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893, +3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3981,3982,3983,3907,3908,3909, +3910,3911,3912,3913,3984,3915,3916,3985,3918,3919,3920,3921,3922,3923,3924,3925, +3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986, +3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3987,3987,3987,3987,3988, +3987,3987,3987,3927,3928,3989,3930,3931,3932,3990,3934,3935,3936,3937,3938,3939, +3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955, +3956,3957,3958,3959,3960,3936,3961,3962,3963,3991,3992,3966,3993,3994,3969,3970, +3971,3972,3973,3987,3987,3987,3987,3987,3995,3986,3996,3996,3996,3996,3996,3996, +3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996, +3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996, }, { 1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237, -1238,1239,1240,1241,1242,1243,1244,1245,4114,4115,4116,1249,1250,1376,1377,1253, -1378,1255,1256,4117,1380,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,4118, -1270,4119,4120,4121,4122,1275,1276,1277,1278,1279,1381,1281,1282,1283,1284,1285, +1238,1239,1240,1241,1242,1243,1244,1245,3997,3998,3999,1249,1250,1376,1377,1253, +1378,1255,1256,4000,1380,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,4001, +1270,4002,4003,4004,4005,1275,1276,1277,1278,1279,1381,1281,1282,1283,1284,1285, 1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301, -1302,1303,1304,1305,4123,1307,1308,1309,1309,1310,1311,1312,1313,1314,1315,1316, +1302,1303,1304,1305,4006,1307,1308,1309,1309,1310,1311,1312,1313,1314,1315,1316, 1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332, -1333,1334,1335,1336,1337,4124,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348, +1333,1334,1335,1336,1337,4007,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 312,1349,1350,4125,1352,4126,1354,4127,1355, 320,1356, 321,1357, + 295, 295, 295, 312,1349,1350,4008,1352,4009,1354,4010,1355, 320,1356, 321,1357, 1358,1359,1360,1361,1362,1363,1364,1383,1366,1359,1384,1361, 332, 333, 334, 335, 336,1368,1369, 338, 339, 320,1370, 295, 295, 295, 295,1372,1373,1374,1375, 295, 347, 348, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, @@ -10620,38 +10487,38 @@ const unsigned short banks[75][256] = 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -4128,4129,4130,4131,4132,4133, 6, 7,4134, 9, 10,4135, 12, 13, 14, 15, -4136,4137,4138,4139, 20,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150, - 32,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164, 46, -4165,4166,4167,4168,4169,4170,4171, 54,4172,4173,4174,4175,4176,4177,4178,4179, -4180,4181,4182, 66,4183,4184, 69,4185,4186,4187,4188, 74, 75, 76, 77, 78, -4189,4190,4191, 82,4192,4193, 85,4194,4195, 88,4196,4197,4198,4199,4200,4201, - 95, 96, 97,4202,4203,4204,4205, 102, 103,4206, 105, 106, 107,4207,4208,4209, -4210, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,4211,4212,4213, 125,4214, +4011,4012,4013,4014,4015,4016, 6, 7,4017, 9, 10,4018, 12, 13, 14, 15, +4019,4020,4021,4022, 20,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033, + 32,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047, 46, +4048,4049,4050,4051,4052,4053,4054, 54,4055,4056,4057,4058,4059,4060,4061,4062, +4063,4064,4065, 66,4066,4067, 69,4068,4069,4070,4071, 74, 75, 76, 77, 78, +4072,4073,4074, 82,4075,4076, 85,4077,4078, 88,4079,4080,4081,4082,4083,4084, + 95, 96, 97,4085,4086,4087,4088, 102, 103,4089, 105, 106, 107,4090,4091,4092, +4093, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,4094,4095,4096, 125,4097, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784, -3785,3786,3787,3788,3786,3789,3790,3786,3791,3786,3792,3793,3794,3795,3796,3797, -3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813, -3814,3815, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656, +3657,3658,3659,3660,3658,3661,3662,3658,3663,3658,3664,3665,3666,3667,3668,3669, +3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685, +3686,3687, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3415,3416, 466,3417, 713,3324,3418, 467,3419, 632,3420,3421,3422,3423,4215,3425, -3426, 598,4216,3428,3429,3430,3431,3432,4217,4218,4219,4220, 759, 437, 438,3435, -3436,3437, 439,3438, 440,4221, 442,4222,3440,3441,3442,3443,2306,4223,3445, 582, -3446,3447, 452,3448,3449,4224,3450,3451,3452, 778,3453,2312, 779,3454,3455,3456, -3457, 769,3458,3459,3460,3461, 663, 664,3462,2316,3463,3464,3465,1299,3466,3467, -3468,3469,4225,3471,3472,3473,4226, 442,3475,3476,3477,3432,3478,1669,3479,3480, -3481,3482,3483,3484,4227, 261,3485,3486,1919,2420,3487,3488, 676,3489,3490,3491, -3492,4228,3494,3495,4229,4230, 680,3497,3498, 462,3499, 455,3500,2421,3501, 465, +3287,3288, 466,3289, 713,3196,3290, 467,3291, 632,3292,3293,3294,3295,4098,3297, +3298, 598,4099,3300,3301,3302,3303,3304,4100,4101,4102,4103, 759, 437, 438,3307, +3308,3309, 439,3310, 440,4104, 442,4105,3312,3313,3314,3315,2306,4106,3317, 582, +3318,3319, 452,3320,3321,4107,3322,3323,3324, 778,3325,2312, 779,3326,3327,3328, +3329, 769,3330,3331,3332,3333, 663, 664,3334,2316,3335,3336,3337,1299,3338,3339, +3340,3341,4108,3343,3344,3345,4109, 442,3347,3348,3349,3304,3350,1669,3351,3352, +3353,3354,3355,3356,4110, 261,3357,3358,1919,2420,3359,3360, 676,3361,3362,3363, +3364,4111,3366,3367,4112,4113, 680,3369,3370, 462,3371, 455,3372,2421,3373, 465, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3772,3773,4231,3777,3776,4232,4233,4234,4235,4236,4237,4238,4239, -4240,3786,4241,3788,3786,3789,3790,3786,3791,3786,3792,2617,3794,3795,3796,3797, -3798,3799,3800,3801,3802, 160,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813, -3814,3815, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295,3644,3645,4114,3649,3648,4115,4116,4117,4118,4119,4120,4121,4122, +4123,3658,4124,3660,3658,3661,3662,3658,3663,3658,3664,2617,3666,3667,3668,3669, +3670,3671,3672,3673,3674, 160,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685, +3686,3687, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, @@ -10666,28 +10533,28 @@ const unsigned short banks[75][256] = 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127,4242,4243,4244, 141,4245,4246,4247,4246,4248,4246,4249,4250, -4251,1954,4252,4253,4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265, -4266,4267,4268,4269,4270,4271, 163,4272, 625,4273,4274,4275,4276,4277,4278,4279, -4280,4281,4282,4283,4284,4285,4286, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127,4125,4126,4127, 141,4128,4129,4130,4129,4131,4129,4132,4133, +4134,1954,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148, +4149,4150,4151,4152,4153,4154, 163,4155, 625,4156,4157,4158,4159,4160,4161,4162, +4163,4164,4165,4166,4167,4168,4169, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, }, { -4287,4288,1553,1554, 181,4289,4290,1555, 185,4291,3625,4292,1559, 188,4293,4294, -4295,1562,4296,4297,1565, 195,4298, 197,4299,4300, 200, 201, 28,1566,1567,4301, -4302,4303,4304,4305,4306,4307,4308,4309,1572,1573, 214, 215, 216, 217, 218, 219, - 220,4310,4311,1575,1576,1577,1578,4312,1579,1580,4313,1581,4314,4315,4316,4317, - 232, 233, 234, 235,4318, 237, 238,4319,1584,1585, 240,1586, 242, 243, 244,1587, - 246,4320,4321,1589, 249, 250, 251,1590, 252,4322, 254, 255,4323,4324,4325,4326, -1595,4327,1596,1597,1598,1599,1600,1601,4328,4329,4330, 267,4331,4332, 270,4333, -4334,4335, 273,1603,4336,1605, 276,4337,4338,4339,4340,1610,4341,4342,4343, 126, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,4344,1470,1613,4345,1615,4346,1475,4347,1477,4348,1479,4349,1481, -1482,4350,1484,4351,4352,4353,1630,4354,2291,4355,1634,3642,1636,1637,1638,1639, -1640,4356,4357,1643,1644,1645,1646,4358, 342,4359,4360,1651,1652,1653,4361,4362, -1656,4363,1658,1659,1660,1661,1662,1663, 295, 295, 295, 295, 295, 295, 295, 295, +4170,4171,1553,1554, 181,4172,4173,1555, 185,4174,3497,4175,1559, 188,4176,4177, +4178,1562,4179,4180,1565, 195,4181, 197,4182,4183, 200, 201, 28,1566,1567,4184, +4185,4186,4187,4188,4189,4190,4191,4192,1572,1573, 214, 215, 216, 217, 218, 219, + 220,4193,4194,1575,1576,3852,1578,4195,1579,1580,4196,4197,4198,4199,4200,4201, + 232, 233, 234, 235,4202, 237, 238,4203,1584,1585, 240,1586,4204, 243, 244,1587, + 246,4205,4206,1589, 249, 250, 251,1590, 252,4207, 254,3889,4208,4209,4210,4211, +1595,4212,1596,1597,4213,1599,1600,1601,4214,4215,4216, 267,4217,4218, 270,4219, +4220,4221,4222,1603,4223,4224, 276,4225,4226,4227,4228,1610,4229,4230,4231, 126, + 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,1662,1663, 295, + 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,4232,4233,4234,4235,4236, +4237,4238,4239,4240,1470,1613,4241,1615,4242,1475,4243,1477,4244,1479,4245,1481, +1482,4246,1484,4247,4248,4249,1630,4250,2291,4251,1634,3514,1636,1637,1638,1639, +1640,4252,4253,1643,1644, 320,4254,4255, 342,4256,4257,4258,4259,1374,4260,4261, +1656,4262,4263,1659,1660,4264,1662,1663, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, @@ -10699,9 +10566,9 @@ const unsigned short banks[75][256] = 2224, 909,2225, 911, 912,2226,2227, 915, 916,2228,2229, 919, 920, 921, 922, 923, 2230, 925, 926, 927, 928, 929, 295, 931, 932, 933, 934, 935,2232,2233, 938,2234, 940, 295, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, - 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966,4366, 968,4367, 295, 295, -4368,4369,4370,4371,4372,4373,4374, 978,4375,4376,4377,4378,4379,4380,4381,4382, -4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393, 975, 971, 972, 973, 974, + 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966,4267, 968,4268, 295, 295, +4269,4270,4271,4272,4273,4274,4275, 978,4276,4277,4278,4279,4280,4281,4282,4283, +4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294, 975, 971, 972, 973, 974, 975, 310, 976, 977, 978, 974,2239, 980,2240, 982,2241, 984,2242, 985,2243, 987, 988,2244, 990, 325,2244, 325, 991,2244,2245,2246, 330, 993,2247,2248,2249, 997, 998,2250,2251,1001,1002,1003, 340,1004,1005,1006,1007,1008,1009, 310,1010,1011, @@ -10710,62 +10577,62 @@ const unsigned short banks[75][256] = 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -3415,4395,3324,3324,4396,3324,3324,3324,3324,3324,3324, 378,3324,3324,3822,3324, -3324,4397,3324,4398,4399,4400,3324,3324,3324, 370,3324,4401,4402,4403,4404,4405, -3324,4406,4407,4408,3438,3438,4409, 442,4410,3324,3324,4411,4412,4411, 676,4413, -4414,3324,3324,4415, 51,3324,3324,3324,4416,3452,4417,3324, 59,4418,4416, 62, -3324,4419,4419,4420, 67,3324, 664,4421,3324,2316,3324,4422, 70,3324,4423, 78, -4424,4425, 81,3324,3324,3324,3324,3324,3324,3324,3324, 90,3324,4426, 93,4427, -3324,3324,3324,3324,3324,3324,3324,4428,3324,3324,3324,3324,3324,3324,3324,3324, -3324,3324,3324,3324,3324,4229,3324,4429,3324,3324,3324,3324,3324,3324,3324,3324, -3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324, -3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324, -3324,3324,3324,4430,4430,4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441, -4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,3324,3324,4454, 154, -4455,4456,4457,3324,3324, 160,3324,3324,3324,4458,4459,4460,4461,4462,4463,3324, -3324,4464, 160,4465,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324, -3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324, -3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324,3324, +3287,4296,3196,3196,4297,3196,3196,3196,3196,3196,3196, 378,3196,3196,3694,3196, +3196,4298,3196,4299,4300,4301,3196,3196,3196, 370,3196,4302,4303,4304,4305,4306, +3196,4307,4308,4309,3310,3310,4310, 442,4311,3196,3196,4312,4313,4312, 676,4314, +4315,3196,3196,4316, 51,3196,3196,3196,4317,3324,4318,3196, 59,4319,4317, 62, +3196,4320,4320,4321, 67,3196, 664,4322,3196,2316,3196,4323, 70,3196,4324, 78, +4325,4326, 81,3196,3196,3196,3196,3196,3196,3196,3196, 90,3196,4327, 93,4328, +3196,3196,3196,3196,3196,3196,3196,4329,3196,3196,3196,3196,3196,3196,3196,3196, +3196,3196,3196,3196,3196,4112,3196,4330,3196,3196,3196,3196,3196,3196,3196,3196, +3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, +3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, +3196,3196,3196,4331,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342, +4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,3196,3196,4355, 154, +4356,4357,4358,3196,3196, 160,3196,3196,3196,4359,4360,4361,4362,4363,4364,3196, +3196,4365, 160,4366,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, +3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, +3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, }, { -3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943, -3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959, -3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975, -3968,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990, -3991,3992,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005, -4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021, -4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037, -4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4466,4049,4050,4051,4052,4053, -4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104, -4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4104,4105,4105,4105,4105,4105, -4105,4105,4105,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067, -4068,4069,4070,3788,4071,4072,3790,4073,3791,4074,4075,3793,4076,4077,4078,4079, -4080,4081,4082,4083,4084,4064,3804,4085,4086,3807,4087,4088,4089,4090,3812,3813, -4091,4092,4093,4105,4105,4105,4105,4105,4105,4104,4113,4113,4113,4113,4113,4113, -4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113, -4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113,4113, +3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815, +3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831, +3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847, +3840,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862, +3863,3864,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877, +3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893, +3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909, +3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,4367,3921,3922,3923,3924,3925, +3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986, +3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3987,3987,3987,3987,3987, +3987,3987,3987,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939, +3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955, +3956,3957,3958,3959,3960,3936,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970, +3971,3972,3973,3987,3987,3987,3987,3987,3995,3986,3996,3996,3996,3996,3996,3996, +3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996, +3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996, }, { -4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482, -4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498, -4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514, -4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,4529,4530, -4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,4544,4545,4546, -4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562, -4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,4574,4575,4576,4577,4578, -4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594, +4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383, +4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399, +4400,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415, +4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4197,4427,4428,4429,4430, +4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4204,4443,4444,4445, +4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461, +4462,4463,4464,4465,4466,4467,4468,4469,4470,4215,4216,4471,4472,4218,4473,4474, +4475,4476,4222,4477,4478,4224,4479,4480,4226,4481,4228,4482,4483,4484,4485,4486, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,4595,4596,4597,4598,4599, -4600,4601,4602,4603,4604,4605,4606,4607,4346,4608,4609,4610,4611,4612,4349,4613, -4614,4615,4616,4617,4352,4618,4619,4354,4620,4621,4622,4623,4624,4625,4626,4627, -4628,4629,4630,4631,4632, 320,4633,4634,4635,4636,4637,4638,4639,1374,4640,4641, -4642,4643,4644,4645,4646,4647,4648,4649, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,4232,4233,4234,4235,4487, +4237,4238,4239,4488,4489,4490,4491,4492,4242,4493,4494,4495,4244,4496,4245,4497, +4498,4499,4500,4501,4248,4502,4503,4250,4504,4505,4506,4507,4508,4509,4510,4511, +4512,4252,4253,4513,4514, 320,4515,4516,4517,4256,4257,4258,4259,1374,4260,4261, +4518,4519,4263,4520,4521,4264,4522,4523, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -4650,4651,4652,4653,4651,4654,4655,4656,4657,4658,4659,4661,4662,4663,4664,4665, -4666,4668,4670,4663,4672,4673,4674,4675,4676,4677,4678, 295, 28, 29, 30, 31, +4524,4525,4526,4527,4525,4528,4529,4530,4531,4532,4533,4535,4536,4537,4538,4539, +4540,4542,4544,4537,4546,4547,4548,4549,4550,4551,4552, 295, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 33, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, @@ -10774,28 +10641,28 @@ const unsigned short banks[75][256] = 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127,4667, 128,4669, 130, 131, 132,4671, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144,4660, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 295, 295, 295, 127,4541, 128,4543, 130, 131, 132,4545, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144,4534, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, { -4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,3423,4689,4693, -3426,4694,4695,3426,4696,4697,4697,4697, 868, 869, 870,4698,4699,4700,4701,4702, -4703,4704,4705,4705,4706,4703,4707,4708,3970,4709,4710,4710,4711,4712,4713,4714, -4715,4716,4717,4717,4718,4224,3450,4719,4720,4721,4722,4723,4724,4720,4720,4725, -3457, 769,3458,3459,4726,4727,4728,4729,4730,4731,4732,4733,4734,4731,1300,4735, -4736,4737,4731,4696,4738,4720,4739,4740,3475,4741,4742,4743,4744,1314,4745,4746, -4747,4748,4749,4742,4742,1322,4750,4751,4752,4753,4754,4753,3423,4755,3970,4756, -4757,1334,4757,4758,4759,4760, 792,4761,1341,1342,1343,1344,4762,4763,4764,1348, +4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,3295,4563,4567, +3298,4568,4569,3298,4570,4571,4571,4571, 868, 869, 870,4572,4573,4574,4575,4576, +4577,4578,4579,4579,4580,4577,4581,4582,3842,4583,4584,4584,4585,4586,4587,4588, +4589,4590,4591,4591,4592,4107,3322,4593,4594,4595,4596,4597,4598,4594,4594,4599, +3329, 769,3330,3331,4600,4601,4602,4603,4604,4605,4606,4607,4608,4605,1300,4609, +4610,4611,4605,4570,4612,4594,4613,4614,3347,4615,4616,4617,4618,1314,4619,4620, +4621,4622,4623,4616,4616,1322,4624,4625,4626,4627,4628,4627,3295,4629,3842,4630, +4631,1334,4631,4632,4633,4634, 792,4635,1341,1342,1343,1344,4636,4637,4638,1348, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,4765,4765,4766,4767,4766,4768,4769,4770,4771,4772,4773,4774,4775, -4776,4777,4778,4779,4780,4781,4782,4783,4784,4777,4785,4786,4787,4788,4789,4790, -4791,4792,4793,4794,4795,4796,4797,4794,4795,4796,4798,4799,4800,4801,1375, 295, -4802,4803, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295,4639,4639,4640,4641,4640,4642,4643,4644,4645,4646,4647,4648,4649, +4650,4651,4652,4653,4654,4655,4656,4657,4658,4651,4659,4660,4661,4662,4663,4664, +4665,4666,4667,4668,4669,4670,4671,4668,4669,4670,4672,4673,4674,4675,1375, 295, +4676,4677, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, }, @@ -10869,8 +10736,8 @@ const AdlBankSetup adlbanksetup[75] = {3, 0, 0, 0, 0}, //Bank 63, TMB (Shadow Warrior) {2, 0, 0, 0, 0}, //Bank 64, DMX (Raptor) {3, 0, 0, 0, 0}, //Bank 65, OP3 (Modded GMOPL by Wohlstand) - {3, 0, 0, 0, 0}, //Bank 66, SB (Jammey O'Connel's bank) - {3, 0, 0, 0, 0}, //Bank 67, TMB (Default bank of Apgee Sound System) + {3, 0, 0, 0, 0}, //Bank 66, SB (Jamie O'Connell's bank) + {3, 0, 0, 0, 0}, //Bank 67, TMB (Default bank of Apogee Sound System) {0, 1, 1, 0, 0}, //Bank 68, WOPL (4op bank by James Alan Nguyen and Wohlstand) {3, 0, 0, 0, 0}, //Bank 69, TMB (Blood) {3, 0, 0, 0, 0}, //Bank 70, TMB (Lee) diff --git a/src/sound/adlmidi/adldata.hh b/src/sound/adlmidi/adldata.hh index 104db82cd..93d4144e0 100644 --- a/src/sound/adlmidi/adldata.hh +++ b/src/sound/adlmidi/adldata.hh @@ -26,6 +26,7 @@ #include #include +#include #pragma pack(push, 1) #define ADLDATA_BYTE_COMPARABLE(T) \ @@ -34,32 +35,32 @@ inline bool operator!=(const T &a, const T &b) \ { return !operator==(a, b); } -extern const struct adldata +struct adldata { uint32_t modulator_E862, carrier_E862; // See below uint8_t modulator_40, carrier_40; // KSL/attenuation settings uint8_t feedconn; // Feedback/connection bits for the channel int8_t finetune; -} adl[]; +}; ADLDATA_BYTE_COMPARABLE(struct adldata) -enum { adlDefaultNumber = 189 }; -extern const struct adlinsdata +struct adlinsdata { enum { Flag_Pseudo4op = 0x01, Flag_NoSound = 0x02, Flag_Real4op = 0x04 }; + enum { Flag_RM_BassDrum = 0x08, Flag_RM_Snare = 0x10, Flag_RM_TomTom = 0x18, + Flag_RM_Cymbal = 0x20, Flag_RM_HiHat = 0x28, Mask_RhythmMode = 0x38 }; + uint16_t adlno1, adlno2; uint8_t tone; uint8_t flags; uint16_t ms_sound_kon; // Number of milliseconds it produces sound; uint16_t ms_sound_koff; + int8_t midi_velocity_offset; double voice2_fine_tune; -} adlins[]; +}; ADLDATA_BYTE_COMPARABLE(struct adlinsdata) -int maxAdlBanks(); -extern const unsigned short banks[][256]; -extern const char* const banknames[]; enum { adlNoteOnMaxTime = 40000 }; @@ -73,9 +74,9 @@ struct adlinsdata2 uint8_t flags; uint16_t ms_sound_kon; // Number of milliseconds it produces sound; uint16_t ms_sound_koff; + int8_t midi_velocity_offset; double voice2_fine_tune; - adlinsdata2() {} - explicit adlinsdata2(const adlinsdata &d); + static adlinsdata2 from_adldata(const adlinsdata &d); }; ADLDATA_BYTE_COMPARABLE(struct adlinsdata2) @@ -85,25 +86,43 @@ ADLDATA_BYTE_COMPARABLE(struct adlinsdata2) /** * @brief Bank global setup */ -extern const struct AdlBankSetup +struct AdlBankSetup { int volumeModel; bool deepTremolo; bool deepVibrato; bool adLibPercussions; bool scaleModulators; -} adlbanksetup[]; +}; + +#ifndef DISABLE_EMBEDDED_BANKS +int maxAdlBanks(); +extern const adldata adl[]; +extern const adlinsdata adlins[]; +extern const unsigned short banks[][256]; +extern const char* const banknames[]; +extern const AdlBankSetup adlbanksetup[]; +#endif /** * @brief Conversion of storage formats */ -inline adlinsdata2::adlinsdata2(const adlinsdata &d) - : tone(d.tone), flags(d.flags), - ms_sound_kon(d.ms_sound_kon), ms_sound_koff(d.ms_sound_koff), - voice2_fine_tune(d.voice2_fine_tune) +inline adlinsdata2 adlinsdata2::from_adldata(const adlinsdata &d) { - adl[0] = ::adl[d.adlno1]; - adl[1] = ::adl[d.adlno2]; + adlinsdata2 ins; + ins.tone = d.tone; + ins.flags = d.flags; + ins.ms_sound_kon = d.ms_sound_kon; + ins.ms_sound_koff = d.ms_sound_koff; + ins.midi_velocity_offset = d.midi_velocity_offset; + ins.voice2_fine_tune = d.voice2_fine_tune; +#ifdef DISABLE_EMBEDDED_BANKS + std::memset(ins.adl, 0, sizeof(adldata) * 2); +#else + ins.adl[0] = ::adl[d.adlno1]; + ins.adl[1] = ::adl[d.adlno2]; +#endif + return ins; } /** diff --git a/src/sound/adlmidi/adlmidi.cpp b/src/sound/adlmidi/adlmidi.cpp index 9210b5be3..12d0e68e2 100644 --- a/src/sound/adlmidi/adlmidi.cpp +++ b/src/sound/adlmidi/adlmidi.cpp @@ -23,13 +23,9 @@ #include "adlmidi_private.hpp" -#ifdef ADLMIDI_HW_OPL -#define MaxCards 1 -#define MaxCards_STR "1" //Why not just "#MaxCards" ? Watcom fails to pass this with "syntax error" :-P -#else -#define MaxCards 100 -#define MaxCards_STR "100" -#endif +/* Unify MIDI player casting and interface between ADLMIDI and OPNMIDI */ +#define GET_MIDI_PLAYER(device) reinterpret_cast((device)->adl_midiPlayer) +typedef MIDIplay MidiPlayer; static ADL_Version adl_version = { ADLMIDI_VERSION_MAJOR, @@ -56,7 +52,7 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate) return NULL; } - MIDIplay *player = new MIDIplay(static_cast(sample_rate)); + MIDIplay *player = new(std::nothrow) MIDIplay(static_cast(sample_rate)); if(!player) { free(midi_device); @@ -64,59 +60,109 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate) return NULL; } midi_device->adl_midiPlayer = player; - adlRefreshNumCards(midi_device); + adlCalculateFourOpChannels(player); return midi_device; } -ADLMIDI_EXPORT int adl_setNumChips(ADL_MIDIPlayer *device, int numCards) +ADLMIDI_EXPORT void adl_close(struct ADL_MIDIPlayer *device) +{ + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + delete play; + device->adl_midiPlayer = NULL; + free(device); + device = NULL; +} + +ADLMIDI_EXPORT int adl_setDeviceIdentifier(ADL_MIDIPlayer *device, unsigned id) +{ + if(!device || id > 0x0f) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->setDeviceId(static_cast(id)); + return 0; +} + +ADLMIDI_EXPORT int adl_setNumChips(ADL_MIDIPlayer *device, int numChips) { if(device == NULL) return -2; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); #ifdef ADLMIDI_HW_OPL - (void)numCards; - play->m_setup.NumCards = 1; + ADL_UNUSED(numChips); + play->m_setup.numChips = 1; #else - play->m_setup.NumCards = static_cast(numCards); + play->m_setup.numChips = static_cast(numChips); #endif - if(play->m_setup.NumCards < 1 || play->m_setup.NumCards > MaxCards) + if(play->m_setup.numChips < 1 || play->m_setup.numChips > ADL_MAX_CHIPS) { - play->setErrorString("number of chips may only be 1.." MaxCards_STR ".\n"); + play->setErrorString("number of chips may only be 1.." ADL_MAX_CHIPS_STR ".\n"); return -1; } - play->opl.NumCards = play->m_setup.NumCards; - adl_reset(device); + int maxFourOps = static_cast(play->m_setup.numChips * 6); - return adlRefreshNumCards(device); + if(play->m_setup.numFourOps > maxFourOps) + play->m_setup.numFourOps = maxFourOps; + else if(play->m_setup.numFourOps < -1) + play->m_setup.numFourOps = -1; + + if(!play->m_synth.setupLocked()) + { + play->m_synth.m_numChips = play->m_setup.numChips; + if(play->m_setup.numFourOps < 0) + adlCalculateFourOpChannels(play, true); + else + play->m_synth.m_numFourOps = static_cast(play->m_setup.numFourOps); + play->partialReset(); + return 0; + } + + return 0; } ADLMIDI_EXPORT int adl_getNumChips(struct ADL_MIDIPlayer *device) { if(device == NULL) return -2; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - if(play) - return (int)play->m_setup.NumCards; - return -2; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return (int)play->m_setup.numChips; +} + +ADLMIDI_EXPORT int adl_getNumChipsObtained(struct ADL_MIDIPlayer *device) +{ + if(device == NULL) + return -2; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return (int)play->m_synth.m_numChips; } ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) { - #ifdef DISABLE_EMBEDDED_BANKS - ADL_UNUSED(device); +#ifdef DISABLE_EMBEDDED_BANKS ADL_UNUSED(bank); - ADLMIDI_ErrorString = "This build of libADLMIDI has no embedded banks. Please load bank by using of adl_openBankFile() or adl_openBankData() functions instead of adl_setBank()"; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->setErrorString("This build of libADLMIDI has no embedded banks. " + "Please load banks by using adl_openBankFile() or " + "adl_openBankData() functions instead of adl_setBank()."); return -1; - #else +#else const uint32_t NumBanks = static_cast(maxAdlBanks()); int32_t bankno = bank; if(bankno < 0) bankno = 0; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); if(static_cast(bankno) >= NumBanks) { char errBuf[150]; @@ -125,30 +171,39 @@ ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) return -1; } - play->m_setup.AdlBank = static_cast(bankno); - play->opl.setEmbeddedBank(play->m_setup.AdlBank); + play->m_setup.bankId = static_cast(bankno); + play->m_synth.setEmbeddedBank(play->m_setup.bankId); play->applySetup(); - return adlRefreshNumCards(device); - #endif + return 0; +#endif } ADLMIDI_EXPORT int adl_getBanksCount() { +#ifndef DISABLE_EMBEDDED_BANKS return maxAdlBanks(); +#else + return 0; +#endif } ADLMIDI_EXPORT const char *const *adl_getBankNames() { +#ifndef DISABLE_EMBEDDED_BANKS return banknames; +#else + return NULL; +#endif } ADLMIDI_EXPORT int adl_reserveBanks(ADL_MIDIPlayer *device, unsigned banks) { if(!device) return -1; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - OPL3::BankMap &map = play->opl.dynamic_banks; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPL3::BankMap &map = play->m_synth.m_insBanks; map.reserve(banks); return (int)map.capacity(); } @@ -161,10 +216,11 @@ ADLMIDI_EXPORT int adl_getBank(ADL_MIDIPlayer *device, const ADL_BankId *idp, in ADL_BankId id = *idp; if(id.lsb > 127 || id.msb > 127 || id.percussive > 1) return -1; - unsigned idnumber = (id.msb << 8) | id.lsb | (id.percussive ? OPL3::PercussionTag : 0); + size_t idnumber = ((id.msb << 8) | id.lsb | (id.percussive ? size_t(OPL3::PercussionTag) : 0)); - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - OPL3::BankMap &map = play->opl.dynamic_banks; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPL3::BankMap &map = play->m_synth.m_insBanks; OPL3::BankMap::iterator it; if(!(flags & ADLMIDI_Bank_Create)) @@ -175,7 +231,7 @@ ADLMIDI_EXPORT int adl_getBank(ADL_MIDIPlayer *device, const ADL_BankId *idp, in } else { - std::pair value; + std::pair value; value.first = idnumber; memset(&value.second, 0, sizeof(value.second)); for (unsigned i = 0; i < 128; ++i) @@ -203,7 +259,7 @@ ADLMIDI_EXPORT int adl_getBankId(ADL_MIDIPlayer *device, const ADL_Bank *bank, A return -1; OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); - unsigned idnumber = it->first; + OPL3::BankMap::key_type idnumber = it->first; id->msb = (idnumber >> 8) & 127; id->lsb = idnumber & 127; id->percussive = (idnumber & OPL3::PercussionTag) ? 1 : 0; @@ -215,8 +271,9 @@ ADLMIDI_EXPORT int adl_removeBank(ADL_MIDIPlayer *device, ADL_Bank *bank) if(!device || !bank) return -1; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - OPL3::BankMap &map = play->opl.dynamic_banks; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPL3::BankMap &map = play->m_synth.m_insBanks; OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); size_t size = map.size(); map.erase(it); @@ -228,8 +285,9 @@ ADLMIDI_EXPORT int adl_getFirstBank(ADL_MIDIPlayer *device, ADL_Bank *bank) if(!device) return -1; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - OPL3::BankMap &map = play->opl.dynamic_banks; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPL3::BankMap &map = play->m_synth.m_insBanks; OPL3::BankMap::iterator it = map.begin(); if(it == map.end()) @@ -244,8 +302,9 @@ ADLMIDI_EXPORT int adl_getNextBank(ADL_MIDIPlayer *device, ADL_Bank *bank) if(!device) return -1; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - OPL3::BankMap &map = play->opl.dynamic_banks; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPL3::BankMap &map = play->m_synth.m_insBanks; OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); if(++it == map.end()) @@ -258,7 +317,7 @@ ADLMIDI_EXPORT int adl_getNextBank(ADL_MIDIPlayer *device, ADL_Bank *bank) ADLMIDI_EXPORT int adl_getInstrument(ADL_MIDIPlayer *device, const ADL_Bank *bank, unsigned index, ADL_Instrument *ins) { if(!device || !bank || index > 127 || !ins) - return 1; + return -1; OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); cvt_FMIns_to_ADLI(*ins, it->second.ins[index]); @@ -269,130 +328,248 @@ ADLMIDI_EXPORT int adl_getInstrument(ADL_MIDIPlayer *device, const ADL_Bank *ban ADLMIDI_EXPORT int adl_setInstrument(ADL_MIDIPlayer *device, ADL_Bank *bank, unsigned index, const ADL_Instrument *ins) { if(!device || !bank || index > 127 || !ins) - return 1; + return -1; if(ins->version != 0) - return 1; + return -1; OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); cvt_ADLI_to_FMIns(it->second.ins[index], *ins); return 0; } +ADLMIDI_EXPORT int adl_loadEmbeddedBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank, int num) +{ + if(!device) + return -1; + +#ifdef DISABLE_EMBEDDED_BANKS + ADL_UNUSED(bank); + ADL_UNUSED(num); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->setErrorString("This build of libADLMIDI has no embedded banks. " + "Please load banks by using adl_openBankFile() or " + "adl_openBankData() functions instead of adl_loadEmbeddedBank()."); + return -1; +#else + if(num < 0 || num >= maxAdlBanks()) + return -1; + + OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); + size_t id = it->first; + + for (unsigned i = 0; i < 128; ++i) { + size_t insno = i + ((id & OPL3::PercussionTag) ? 128 : 0); + size_t adlmeta = ::banks[num][insno]; + it->second.ins[i] = adlinsdata2::from_adldata(::adlins[adlmeta]); + } + return 0; +#endif +} + ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4) { if(!device) return -1; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - if((unsigned int)ops4 > 6 * play->m_setup.NumCards) + + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + if(ops4 > 6 * static_cast(play->m_setup.numChips)) { char errBuff[250]; - snprintf(errBuff, 250, "number of four-op channels may only be 0..%u when %u OPL3 cards are used.\n", (6 * (play->m_setup.NumCards)), play->m_setup.NumCards); + snprintf(errBuff, 250, "number of four-op channels may only be 0..%u when %u OPL3 cards are used.\n", (6 * (play->m_setup.numChips)), play->m_setup.numChips); play->setErrorString(errBuff); return -1; } - play->m_setup.NumFourOps = static_cast(ops4); - play->opl.NumFourOps = play->m_setup.NumFourOps; + play->m_setup.numFourOps = ops4; + if(!play->m_synth.setupLocked()) + { + if(play->m_setup.numFourOps < 0) + adlCalculateFourOpChannels(play, true); + else + play->m_synth.m_numFourOps = static_cast(play->m_setup.numFourOps); + play->m_synth.updateChannelCategories(); + } - return 0; //adlRefreshNumCards(device); + return 0; } ADLMIDI_EXPORT int adl_getNumFourOpsChn(struct ADL_MIDIPlayer *device) { if(!device) - return -1; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - if(play) - return (int)play->m_setup.NumFourOps; - return -1; + return -2; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_setup.numFourOps; } +ADLMIDI_EXPORT int adl_getNumFourOpsChnObtained(struct ADL_MIDIPlayer *device) +{ + if(!device) + return -2; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return (int)play->m_synth.m_numFourOps; +} + + ADLMIDI_EXPORT void adl_setPercMode(ADL_MIDIPlayer *device, int percmod) { if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->m_setup.AdlPercussionMode = percmod; - play->opl.AdlPercussionMode = play->m_setup.AdlPercussionMode < 0 ? - play->opl.dynamic_bank_setup.adLibPercussions : - (play->m_setup.AdlPercussionMode != 0); - play->opl.updateFlags(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.rhythmMode = percmod; + if(!play->m_synth.setupLocked()) + { + play->m_synth.m_rhythmMode = play->m_setup.rhythmMode < 0 ? + (play->m_synth.m_insBankSetup.adLibPercussions) : + (play->m_setup.rhythmMode != 0); + play->m_synth.updateChannelCategories(); + } } ADLMIDI_EXPORT void adl_setHVibrato(ADL_MIDIPlayer *device, int hvibro) { if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->m_setup.HighVibratoMode = hvibro; - play->opl.HighVibratoMode = play->m_setup.HighVibratoMode < 0 ? - play->opl.dynamic_bank_setup.deepVibrato : - (play->m_setup.HighVibratoMode != 0); - play->opl.updateDeepFlags(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.deepVibratoMode = hvibro; + if(!play->m_synth.setupLocked()) + { + play->m_synth.m_deepVibratoMode = play->m_setup.deepVibratoMode < 0 ? + play->m_synth.m_insBankSetup.deepVibrato : + (play->m_setup.deepVibratoMode != 0); + play->m_synth.commitDeepFlags(); + } +} + +ADLMIDI_EXPORT int adl_getHVibrato(struct ADL_MIDIPlayer *device) +{ + if(!device) return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_synth.m_deepVibratoMode; } ADLMIDI_EXPORT void adl_setHTremolo(ADL_MIDIPlayer *device, int htremo) { if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->m_setup.HighTremoloMode = htremo; - play->opl.HighTremoloMode = play->m_setup.HighTremoloMode < 0 ? - play->opl.dynamic_bank_setup.deepTremolo : - (play->m_setup.HighTremoloMode != 0); - play->opl.updateDeepFlags(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.deepTremoloMode = htremo; + if(!play->m_synth.setupLocked()) + { + play->m_synth.m_deepTremoloMode = play->m_setup.deepTremoloMode < 0 ? + play->m_synth.m_insBankSetup.deepTremolo : + (play->m_setup.deepTremoloMode != 0); + play->m_synth.commitDeepFlags(); + } +} + +ADLMIDI_EXPORT int adl_getHTremolo(struct ADL_MIDIPlayer *device) +{ + if(!device) return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_synth.m_deepTremoloMode; } ADLMIDI_EXPORT void adl_setScaleModulators(ADL_MIDIPlayer *device, int smod) { - if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->m_setup.ScaleModulators = smod; - play->opl.ScaleModulators = play->m_setup.ScaleModulators < 0 ? - play->opl.dynamic_bank_setup.scaleModulators : - (play->m_setup.ScaleModulators != 0); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.scaleModulators = smod; + if(!play->m_synth.setupLocked()) + { + play->m_synth.m_scaleModulators = play->m_setup.scaleModulators < 0 ? + play->m_synth.m_insBankSetup.scaleModulators : + (play->m_setup.scaleModulators != 0); + } } ADLMIDI_EXPORT void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *device, int fr_brightness) { - if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->m_setup.fullRangeBrightnessCC74 = (fr_brightness != 0); } ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn) { - if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->m_setup.loopingIsEnabled = (loopEn != 0); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + play->m_sequencer.setLoopEnabled(loopEn != 0); +#else + ADL_UNUSED(loopEn); +#endif +} + +ADLMIDI_EXPORT void adl_setSoftPanEnabled(ADL_MIDIPlayer *device, int softPanEn) +{ + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_synth.m_softPanning = (softPanEn != 0); } /* !!!DEPRECATED!!! */ ADLMIDI_EXPORT void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol) { - if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->m_setup.LogarithmicVolumes = (logvol != 0); - if(play->m_setup.LogarithmicVolumes) - play->opl.ChangeVolumeRangesModel(ADLMIDI_VolumeModel_NativeOPL3); - else - play->opl.ChangeVolumeRangesModel(static_cast(play->opl.m_volumeScale)); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.logarithmicVolumes = (logvol != 0); + if(!play->m_synth.setupLocked()) + { + if(play->m_setup.logarithmicVolumes) + play->m_synth.setVolumeScaleModel(ADLMIDI_VolumeModel_NativeOPL3); + else + play->m_synth.setVolumeScaleModel(static_cast(play->m_synth.m_volumeScale)); + } } ADLMIDI_EXPORT void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel) { - if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->m_setup.VolumeModel = volumeModel; - if(play->m_setup.VolumeModel == ADLMIDI_VolumeModel_AUTO)//Use bank default volume model - play->opl.m_volumeScale = (OPL3::VolumesScale)play->opl.dynamic_bank_setup.volumeModel; - else - play->opl.ChangeVolumeRangesModel(static_cast(volumeModel)); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.volumeScaleModel = volumeModel; + if(!play->m_synth.setupLocked()) + { + if(play->m_setup.volumeScaleModel == ADLMIDI_VolumeModel_AUTO)//Use bank default volume model + play->m_synth.m_volumeScale = (OPL3::VolumesScale)play->m_synth.m_insBankSetup.volumeModel; + else + play->m_synth.setVolumeScaleModel(static_cast(volumeModel)); + } +} + +ADLMIDI_EXPORT int adl_getVolumeRangeModel(struct ADL_MIDIPlayer *device) +{ + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_synth.getVolumeScaleModel(); } ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *filePath) { - if(device && device->adl_midiPlayer) + if(device) { - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadBank(filePath)) { @@ -401,7 +578,8 @@ ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *f play->setErrorString("ADL MIDI: Can't load file"); return -1; } - else return adlRefreshNumCards(device); + else + return adlCalculateFourOpChannels(play, true); } ADLMIDI_ErrorString = "Can't load file: ADLMIDI is not initialized"; @@ -410,9 +588,10 @@ ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *f ADLMIDI_EXPORT int adl_openBankData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size) { - if(device && device->adl_midiPlayer) + if(device) { - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadBank(mem, static_cast(size))) { @@ -421,7 +600,8 @@ ADLMIDI_EXPORT int adl_openBankData(struct ADL_MIDIPlayer *device, const void *m play->setErrorString("ADL MIDI: Can't load data from memory"); return -1; } - else return adlRefreshNumCards(device); + else + return adlCalculateFourOpChannels(play, true); } ADLMIDI_ErrorString = "Can't load file: ADL MIDI is not initialized"; @@ -430,9 +610,10 @@ ADLMIDI_EXPORT int adl_openBankData(struct ADL_MIDIPlayer *device, const void *m ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, const char *filePath) { - if(device && device->adl_midiPlayer) + if(device) { - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadMIDI(filePath)) @@ -444,7 +625,7 @@ ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, const char *filePath) } else return 0; #else - (void)filePath; + ADL_UNUSED(filePath); play->setErrorString("ADLMIDI: MIDI Sequencer is not supported in this build of library!"); return -1; #endif //ADLMIDI_DISABLE_MIDI_SEQUENCER @@ -456,9 +637,10 @@ ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, const char *filePath) ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, const void *mem, unsigned long size) { - if(device && device->adl_midiPlayer) + if(device) { - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadMIDI(mem, static_cast(size))) @@ -470,7 +652,8 @@ ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, const void *mem, unsigne } else return 0; #else - (void)mem;(void)size; + ADL_UNUSED(mem); + ADL_UNUSED(size); play->setErrorString("ADLMIDI: MIDI Sequencer is not supported in this build of library!"); return -1; #endif //ADLMIDI_DISABLE_MIDI_SEQUENCER @@ -489,13 +672,14 @@ ADLMIDI_EXPORT const char *adl_chipEmulatorName(struct ADL_MIDIPlayer *device) { if(device) { - #ifndef ADLMIDI_HW_OPL - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - if(play && !play->opl.cardsOP2.empty()) - return play->opl.cardsOP2[0]->emulatorName(); - #else +#ifndef ADLMIDI_HW_OPL + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + if(!play->m_synth.m_chips.empty()) + return play->m_synth.m_chips[0]->emulatorName(); +#else return "Hardware OPL3 chip on 0x330"; - #endif +#endif } return "Unknown"; } @@ -504,11 +688,12 @@ ADLMIDI_EXPORT int adl_switchEmulator(struct ADL_MIDIPlayer *device, int emulato { if(device) { - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - if(play && (emulator >= 0) && (emulator < ADLMIDI_EMU_end)) + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + if(adl_isEmulatorAvailable(emulator)) { play->m_setup.emulator = emulator; - adl_reset(device); + play->partialReset(); return 0; } play->setErrorString("OPL3 MIDI: Unknown emulation core!"); @@ -521,13 +706,12 @@ ADLMIDI_EXPORT int adl_setRunAtPcmRate(ADL_MIDIPlayer *device, int enabled) { if(device) { - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - if(play) - { - play->m_setup.runAtPcmRate = (enabled != 0); - adl_reset(device); - return 0; - } + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.runAtPcmRate = (enabled != 0); + if(!play->m_synth.setupLocked()) + play->partialReset(); + return 0; } return -1; } @@ -556,164 +740,193 @@ ADLMIDI_EXPORT const char *adl_errorInfo(struct ADL_MIDIPlayer *device) { if(!device) return adl_errorString(); - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); if(!play) return adl_errorString(); return play->getErrorString().c_str(); } -ADLMIDI_EXPORT const char *adl_getMusicTitle(struct ADL_MIDIPlayer *device) -{ - if(!device) - return ""; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - if(!play) - return ""; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - return play->musTitle.c_str(); - #else - return ""; - #endif -} - -ADLMIDI_EXPORT void adl_close(struct ADL_MIDIPlayer *device) -{ - if(device->adl_midiPlayer) - delete reinterpret_cast(device->adl_midiPlayer); - device->adl_midiPlayer = NULL; - free(device); - device = NULL; -} - ADLMIDI_EXPORT void adl_reset(struct ADL_MIDIPlayer *device) { if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->m_setup.tick_skip_samples_delay = 0; - play->opl.runAtPcmRate = play->m_setup.runAtPcmRate; - play->opl.Reset(play->m_setup.emulator, play->m_setup.PCM_RATE, play); - play->ch.clear(); - play->ch.resize((size_t)play->opl.NumChannels); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->partialReset(); + play->resetMIDI(); } ADLMIDI_EXPORT double adl_totalTimeLength(struct ADL_MIDIPlayer *device) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - return reinterpret_cast(device->adl_midiPlayer)->timeLength(); - #else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.timeLength(); +#else + ADL_UNUSED(device); return -1.0; - #endif +#endif } ADLMIDI_EXPORT double adl_loopStartTime(struct ADL_MIDIPlayer *device) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - return reinterpret_cast(device->adl_midiPlayer)->getLoopStart(); - #else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getLoopStart(); +#else + ADL_UNUSED(device); return -1.0; - #endif +#endif } ADLMIDI_EXPORT double adl_loopEndTime(struct ADL_MIDIPlayer *device) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - return reinterpret_cast(device->adl_midiPlayer)->getLoopEnd(); - #else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getLoopEnd(); +#else + ADL_UNUSED(device); return -1.0; - #endif +#endif } ADLMIDI_EXPORT double adl_positionTell(struct ADL_MIDIPlayer *device) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - return reinterpret_cast(device->adl_midiPlayer)->tell(); - #else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.tell(); +#else + ADL_UNUSED(device); return -1.0; - #endif +#endif } ADLMIDI_EXPORT void adl_positionSeek(struct ADL_MIDIPlayer *device, double seconds) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + if(seconds < 0.0) + return;//Seeking negative position is forbidden! :-P if(!device) return; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - reinterpret_cast(device->adl_midiPlayer)->seek(seconds); - #endif + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_panic(); + play->m_setup.delay = play->m_sequencer.seek(seconds, play->m_setup.mindelay); + play->m_setup.carry = 0.0; +#else + ADL_UNUSED(device); + ADL_UNUSED(seconds); +#endif } ADLMIDI_EXPORT void adl_positionRewind(struct ADL_MIDIPlayer *device) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - reinterpret_cast(device->adl_midiPlayer)->rewind(); - #endif + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_panic(); + play->m_sequencer.rewind(); +#else + ADL_UNUSED(device); +#endif } ADLMIDI_EXPORT void adl_setTempo(struct ADL_MIDIPlayer *device, double tempo) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device || (tempo <= 0.0)) return; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - reinterpret_cast(device->adl_midiPlayer)->setTempo(tempo); - #endif + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_sequencer.setTempo(tempo); +#else + ADL_UNUSED(device); + ADL_UNUSED(tempo); +#endif +} + + +ADLMIDI_EXPORT int adl_describeChannels(struct ADL_MIDIPlayer *device, char *str, char *attr, size_t size) +{ + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->describeChannels(str, attr, size); + return 0; } ADLMIDI_EXPORT const char *adl_metaMusicTitle(struct ADL_MIDIPlayer *device) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return ""; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - return reinterpret_cast(device->adl_midiPlayer)->musTitle.c_str(); - #else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getMusicTitle().c_str(); +#else + ADL_UNUSED(device); return ""; - #endif +#endif } ADLMIDI_EXPORT const char *adl_metaMusicCopyright(struct ADL_MIDIPlayer *device) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return ""; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - return reinterpret_cast(device->adl_midiPlayer)->musCopyright.c_str(); - #else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getMusicCopyright().c_str(); +#else + ADL_UNUSED(device); return ""; - #endif +#endif } ADLMIDI_EXPORT size_t adl_metaTrackTitleCount(struct ADL_MIDIPlayer *device) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return 0; -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - return reinterpret_cast(device->adl_midiPlayer)->musTrackTitles.size(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getTrackTitles().size(); #else + ADL_UNUSED(device); return 0; #endif } ADLMIDI_EXPORT const char *adl_metaTrackTitle(struct ADL_MIDIPlayer *device, size_t index) { - if(!device) - return 0; #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - if(index >= play->musTrackTitles.size()) + if(!device) + return ""; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + const std::vector &titles = play->m_sequencer.getTrackTitles(); + if(index >= titles.size()) return "INVALID"; - return play->musTrackTitles[index].c_str(); + return titles[index].c_str(); #else - (void)device; (void)index; + ADL_UNUSED(device); + ADL_UNUSED(index); return "NOT SUPPORTED"; #endif } @@ -721,11 +934,14 @@ ADLMIDI_EXPORT const char *adl_metaTrackTitle(struct ADL_MIDIPlayer *device, siz ADLMIDI_EXPORT size_t adl_metaMarkerCount(struct ADL_MIDIPlayer *device) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return 0; -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - return reinterpret_cast(device->adl_midiPlayer)->musMarkers.size(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getMarkers().size(); #else + ADL_UNUSED(device); return 0; #endif } @@ -733,38 +949,56 @@ ADLMIDI_EXPORT size_t adl_metaMarkerCount(struct ADL_MIDIPlayer *device) ADLMIDI_EXPORT Adl_MarkerEntry adl_metaMarker(struct ADL_MIDIPlayer *device, size_t index) { struct Adl_MarkerEntry marker; - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - if(!device || !play || (index >= play->musMarkers.size())) + +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + if(!device) { marker.label = "INVALID"; marker.pos_time = 0.0; marker.pos_ticks = 0; return marker; } - else + + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + + const std::vector &markers = play->m_sequencer.getMarkers(); + if(index >= markers.size()) { - MIDIplay::MIDI_MarkerEntry &mk = play->musMarkers[index]; - marker.label = mk.label.c_str(); - marker.pos_time = mk.pos_time; - marker.pos_ticks = (unsigned long)mk.pos_ticks; + marker.label = "INVALID"; + marker.pos_time = 0.0; + marker.pos_ticks = 0; + return marker; } - #else - (void)device; (void)index; + + const MidiSequencer::MIDI_MarkerEntry &mk = markers[index]; + marker.label = mk.label.c_str(); + marker.pos_time = mk.pos_time; + marker.pos_ticks = (unsigned long)mk.pos_ticks; +#else + ADL_UNUSED(device); + ADL_UNUSED(index); marker.label = "NOT SUPPORTED"; marker.pos_time = 0.0; marker.pos_ticks = 0; - #endif +#endif return marker; } ADLMIDI_EXPORT void adl_setRawEventHook(struct ADL_MIDIPlayer *device, ADL_RawEventHook rawEventHook, void *userData) { +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->hooks.onEvent = rawEventHook; - play->hooks.onEvent_userData = userData; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_sequencerInterface.onEvent = rawEventHook; + play->m_sequencerInterface.onEvent_userData = userData; +#else + ADL_UNUSED(device); + ADL_UNUSED(rawEventHook); + ADL_UNUSED(userData); +#endif } /* Set note hook */ @@ -772,7 +1006,8 @@ ADLMIDI_EXPORT void adl_setNoteHook(struct ADL_MIDIPlayer *device, ADL_NoteHook { if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->hooks.onNote = noteHook; play->hooks.onNote_userData = userData; } @@ -782,12 +1017,19 @@ ADLMIDI_EXPORT void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_D { if(!device) return; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->hooks.onDebugMessage = debugMessageHook; play->hooks.onDebugMessage_userData = userData; +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + play->m_sequencerInterface.onDebugMessage = debugMessageHook; + play->m_sequencerInterface.onDebugMessage_userData = userData; +#endif } #ifndef ADLMIDI_HW_OPL + +# ifndef __WATCOMC__ template static void CopySamplesRaw(ADL_UInt8 *dstLeft, ADL_UInt8 *dstRight, const int32_t *src, size_t frameCount, unsigned sampleOffset) @@ -804,8 +1046,8 @@ static void CopySamplesTransformed(ADL_UInt8 *dstLeft, ADL_UInt8 *dstRight, cons Ret(&transform)(int32_t)) { for(size_t i = 0; i < frameCount; ++i) { - *(Dst *)(dstLeft + (i * sampleOffset)) = (Dst)transform(src[2 * i]); - *(Dst *)(dstRight + (i * sampleOffset)) = (Dst)transform(src[(2 * i) + 1]); + *(Dst *)(dstLeft + (i * sampleOffset)) = static_cast(transform(src[2 * i])); + *(Dst *)(dstRight + (i * sampleOffset)) = static_cast(transform(src[(2 * i) + 1])); } } @@ -919,7 +1161,61 @@ static int SendStereoAudio(int samples_requested, return 0; } -#endif +# else // __WATCOMC__ + +/* + Workaround for OpenWattcom where templates are declared above are causing compiler to be crashed +*/ +static void CopySamplesTransformed(ADL_UInt8 *dstLeft, ADL_UInt8 *dstRight, const int32_t *src, + size_t frameCount, unsigned sampleOffset, + int32_t(&transform)(int32_t)) +{ + for(size_t i = 0; i < frameCount; ++i) { + *(int16_t *)(dstLeft + (i * sampleOffset)) = (int16_t)transform(src[2 * i]); + *(int16_t *)(dstRight + (i * sampleOffset)) = (int16_t)transform(src[(2 * i) + 1]); + } +} + +static int SendStereoAudio(int samples_requested, + ssize_t in_size, + int32_t *_in, + ssize_t out_pos, + ADL_UInt8 *left, + ADL_UInt8 *right, + const ADLMIDI_AudioFormat *format) +{ + if(!in_size) + return 0; + size_t outputOffset = static_cast(out_pos); + size_t inSamples = static_cast(in_size * 2); + size_t maxSamples = static_cast(samples_requested) - outputOffset; + size_t toCopy = std::min(maxSamples, inSamples); + + ADLMIDI_SampleType sampleType = format->type; + const unsigned containerSize = format->containerSize; + const unsigned sampleOffset = format->sampleOffset; + + left += (outputOffset / 2) * sampleOffset; + right += (outputOffset / 2) * sampleOffset; + + if(sampleType == ADLMIDI_SampleType_U16) + { + switch(containerSize) { + case sizeof(int16_t): + CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, adl_cvtS16); + break; + default: + return -1; + } + } + else + return -1; + return 0; +} +# endif // __WATCOM__ + +#endif // ADLMIDI_HW_OPL + ADLMIDI_EXPORT int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short *out) { @@ -930,23 +1226,25 @@ ADLMIDI_EXPORT int adl_playFormat(ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *out_left, ADL_UInt8 *out_right, const ADLMIDI_AudioFormat *format) { - #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - #ifdef ADLMIDI_HW_OPL - (void)device; - (void)sampleCount; - (void)out_left; - (void)out_right; - (void)format; +#if defined(ADLMIDI_DISABLE_MIDI_SEQUENCER) || defined(ADLMIDI_HW_OPL) + ADL_UNUSED(device); + ADL_UNUSED(sampleCount); + ADL_UNUSED(out_left); + ADL_UNUSED(out_right); + ADL_UNUSED(format); return 0; - #else +#endif + +#if !defined(ADLMIDI_DISABLE_MIDI_SEQUENCER) && !defined(ADLMIDI_HW_OPL) sampleCount -= sampleCount % 2; //Avoid even sample requests if(sampleCount < 0) return 0; if(!device) return 0; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - MIDIplay::Setup &setup = player->m_setup; + MidiPlayer *player = GET_MIDI_PLAYER(device); + assert(player); + MidiPlayer::Setup &setup = player->m_setup; ssize_t gotten_len = 0; ssize_t n_periodCountStereo = 512; @@ -966,16 +1264,16 @@ ADLMIDI_EXPORT int adl_playFormat(ADL_MIDIPlayer *device, int sampleCount, else { setup.delay -= eat_delay; - setup.carry += setup.PCM_RATE * eat_delay; + setup.carry += double(setup.PCM_RATE) * eat_delay; n_periodCountStereo = static_cast(setup.carry); - setup.carry -= n_periodCountStereo; + setup.carry -= double(n_periodCountStereo); } //if(setup.SkipForward > 0) // setup.SkipForward -= 1; //else { - if((player->atEnd) && (setup.delay <= 0.0)) + if((player->m_sequencer.positionAtEnd()) && (setup.delay <= 0.0)) break;//Stop to fetch samples at reaching the song end with disabled loop ssize_t leftSamples = left / 2; @@ -990,18 +1288,18 @@ ADLMIDI_EXPORT int adl_playFormat(ADL_MIDIPlayer *device, int sampleCount, ssize_t in_generatedPhys = in_generatedStereo * 2; //! Unsigned total sample count //fill buffer with zeros - int32_t *out_buf = player->outBuf; + int32_t *out_buf = player->m_outBuf; std::memset(out_buf, 0, static_cast(in_generatedPhys) * sizeof(out_buf[0])); - unsigned int chips = player->opl.NumCards; + unsigned int chips = player->m_synth.m_numChips; if(chips == 1) { - player->opl.cardsOP2[0]->generate32(out_buf, (size_t)in_generatedStereo); + player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); } else if(n_periodCountStereo > 0) { /* Generate data from every chip and mix result */ for(size_t card = 0; card < chips; ++card) - player->opl.cardsOP2[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); + player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); } /* Process it */ @@ -1024,10 +1322,7 @@ ADLMIDI_EXPORT int adl_playFormat(ADL_MIDIPlayer *device, int sampleCount, } return static_cast(gotten_len); - #endif - #else - return 0; - #endif //ADLMIDI_DISABLE_MIDI_SEQUENCER +#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER } @@ -1040,22 +1335,23 @@ ADLMIDI_EXPORT int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleC ADL_UInt8 *out_left, ADL_UInt8 *out_right, const ADLMIDI_AudioFormat *format) { - #ifdef ADLMIDI_HW_OPL - (void)device; - (void)sampleCount; - (void)out_left; - (void)out_right; - (void)format; +#ifdef ADLMIDI_HW_OPL + ADL_UNUSED(device); + ADL_UNUSED(sampleCount); + ADL_UNUSED(out_left); + ADL_UNUSED(out_right); + ADL_UNUSED(format); return 0; - #else +#else sampleCount -= sampleCount % 2; //Avoid even sample requests if(sampleCount < 0) return 0; if(!device) return 0; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - MIDIplay::Setup &setup = player->m_setup; + MidiPlayer *player = GET_MIDI_PLAYER(device); + assert(player); + MidiPlayer::Setup &setup = player->m_setup; ssize_t gotten_len = 0; ssize_t n_periodCountStereo = 512; @@ -1068,9 +1364,9 @@ ADLMIDI_EXPORT int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleC {//... const double eat_delay = delay < setup.maxdelay ? delay : setup.maxdelay; delay -= eat_delay; - setup.carry += setup.PCM_RATE * eat_delay; + setup.carry += double(setup.PCM_RATE) * eat_delay; n_periodCountStereo = static_cast(setup.carry); - setup.carry -= n_periodCountStereo; + setup.carry -= double(n_periodCountStereo); { ssize_t leftSamples = left / 2; @@ -1082,16 +1378,16 @@ ADLMIDI_EXPORT int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleC ssize_t in_generatedPhys = in_generatedStereo * 2; //! Unsigned total sample count //fill buffer with zeros - int32_t *out_buf = player->outBuf; + int32_t *out_buf = player->m_outBuf; std::memset(out_buf, 0, static_cast(in_generatedPhys) * sizeof(out_buf[0])); - unsigned int chips = player->opl.NumCards; + unsigned int chips = player->m_synth.m_numChips; if(chips == 1) - player->opl.cardsOP2[0]->generate32(out_buf, (size_t)in_generatedStereo); + player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); else if(n_periodCountStereo > 0) { /* Generate data from every chip and mix result */ for(unsigned card = 0; card < chips; ++card) - player->opl.cardsOP2[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); + player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); } /* Process it */ if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1) @@ -1101,25 +1397,26 @@ ADLMIDI_EXPORT int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleC gotten_len += (in_generatedPhys) /* - setup.stored_samples*/; } - player->TickIteratos(eat_delay); + player->TickIterators(eat_delay); }//... } return static_cast(gotten_len); - #endif +#endif } -ADLMIDI_EXPORT double adl_tickEvents(struct ADL_MIDIPlayer *device, double seconds, double granuality) +ADLMIDI_EXPORT double adl_tickEvents(struct ADL_MIDIPlayer *device, double seconds, double granulality) { #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return -1.0; - return player->Tick(seconds, granuality); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->Tick(seconds, granulality); #else - (void)seconds; (void)granuality; + ADL_UNUSED(device); + ADL_UNUSED(seconds); + ADL_UNUSED(granulality); return -1.0; #endif } @@ -1129,141 +1426,210 @@ ADLMIDI_EXPORT int adl_atEnd(struct ADL_MIDIPlayer *device) #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER if(!device) return 1; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return 1; - return (int)player->atEnd; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return (int)play->m_sequencer.positionAtEnd(); #else + ADL_UNUSED(device); return 1; #endif } +ADLMIDI_EXPORT size_t adl_trackCount(struct ADL_MIDIPlayer *device) +{ +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + if(!device) + return 0; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getTrackCount(); +#else + ADL_UNUSED(device); + return 0; +#endif +} + +ADLMIDI_EXPORT int adl_setTrackOptions(struct ADL_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions) +{ +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + MidiSequencer &seq = play->m_sequencer; + + unsigned enableFlag = trackOptions & 3; + trackOptions &= ~3u; + + // handle on/off/solo + switch(enableFlag) + { + default: + break; + case ADLMIDI_TrackOption_On: + case ADLMIDI_TrackOption_Off: + if(!seq.setTrackEnabled(trackNumber, enableFlag == ADLMIDI_TrackOption_On)) + return -1; + break; + case ADLMIDI_TrackOption_Solo: + seq.setSoloTrack(trackNumber); + break; + } + + // handle others... + if(trackOptions != 0) + return -1; + + return 0; + +#else + ADL_UNUSED(device); + ADL_UNUSED(trackNumber); + ADL_UNUSED(trackOptions); + return -1; +#endif +} + +ADLMIDI_EXPORT int adl_setTriggerHandler(struct ADL_MIDIPlayer *device, ADL_TriggerHandler handler, void *userData) +{ +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + MidiSequencer &seq = play->m_sequencer; + seq.setTriggerHandler(handler, userData); + return 0; +#else + ADL_UNUSED(device); + ADL_UNUSED(handler); + ADL_UNUSED(userData); + return -1; +#endif +} + ADLMIDI_EXPORT void adl_panic(struct ADL_MIDIPlayer *device) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_panic(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_panic(); } ADLMIDI_EXPORT void adl_rt_resetState(struct ADL_MIDIPlayer *device) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_ResetState(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_ResetState(); } ADLMIDI_EXPORT int adl_rt_noteOn(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 velocity) { if(!device) return 0; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return 0; - return (int)player->realTime_NoteOn(channel, note, velocity); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return (int)play->realTime_NoteOn(channel, note, velocity); } ADLMIDI_EXPORT void adl_rt_noteOff(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_NoteOff(channel, note); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_NoteOff(channel, note); } ADLMIDI_EXPORT void adl_rt_noteAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 atVal) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_NoteAfterTouch(channel, note, atVal); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_NoteAfterTouch(channel, note, atVal); } ADLMIDI_EXPORT void adl_rt_channelAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 atVal) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_ChannelAfterTouch(channel, atVal); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_ChannelAfterTouch(channel, atVal); } ADLMIDI_EXPORT void adl_rt_controllerChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 type, ADL_UInt8 value) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_Controller(channel, type, value); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_Controller(channel, type, value); } ADLMIDI_EXPORT void adl_rt_patchChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 patch) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_PatchChange(channel, patch); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_PatchChange(channel, patch); } ADLMIDI_EXPORT void adl_rt_pitchBend(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt16 pitch) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_PitchBend(channel, pitch); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_PitchBend(channel, pitch); } ADLMIDI_EXPORT void adl_rt_pitchBendML(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb, ADL_UInt8 lsb) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_PitchBend(channel, msb, lsb); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_PitchBend(channel, msb, lsb); } ADLMIDI_EXPORT void adl_rt_bankChangeLSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 lsb) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_BankChangeLSB(channel, lsb); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_BankChangeLSB(channel, lsb); } ADLMIDI_EXPORT void adl_rt_bankChangeMSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_BankChangeMSB(channel, msb); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_BankChangeMSB(channel, msb); } ADLMIDI_EXPORT void adl_rt_bankChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_SInt16 bank) { if(!device) return; - MIDIplay *player = reinterpret_cast(device->adl_midiPlayer); - if(!player) - return; - player->realTime_BankChange(channel, (uint16_t)bank); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_BankChange(channel, (uint16_t)bank); +} + +ADLMIDI_EXPORT int adl_rt_systemExclusive(struct ADL_MIDIPlayer *device, const ADL_UInt8 *msg, size_t size) +{ + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->realTime_SysEx(msg, size); } diff --git a/src/sound/adlmidi/adlmidi.h b/src/sound/adlmidi/adlmidi.h index 51cd968d0..352458773 100644 --- a/src/sound/adlmidi/adlmidi.h +++ b/src/sound/adlmidi/adlmidi.h @@ -29,8 +29,8 @@ extern "C" { #endif #define ADLMIDI_VERSION_MAJOR 1 -#define ADLMIDI_VERSION_MINOR 3 -#define ADLMIDI_VERSION_PATCHLEVEL 3 +#define ADLMIDI_VERSION_MINOR 4 +#define ADLMIDI_VERSION_PATCHLEVEL 0 #define ADLMIDI_TOSTR_I(s) #s #define ADLMIDI_TOSTR(s) ADLMIDI_TOSTR_I(s) @@ -55,392 +55,1187 @@ typedef char ADL_SInt8; typedef short ADL_SInt16; #endif +/* == Deprecated function markers == */ + +#if defined(_MSC_VER) /* MSVC */ +# if _MSC_VER >= 1500 /* MSVC 2008 */ + /*! Indicates that the following function is deprecated. */ +# define ADLMIDI_DEPRECATED(message) __declspec(deprecated(message)) +# endif +#endif /* defined(_MSC_VER) */ + +#ifdef __clang__ +# if __has_extension(attribute_deprecated_with_message) +# define ADLMIDI_DEPRECATED(message) __attribute__((deprecated(message))) +# endif +#elif defined __GNUC__ /* not clang (gcc comes later since clang emulates gcc) */ +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define ADLMIDI_DEPRECATED(message) __attribute__((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define ADLMIDI_DEPRECATED(message) __attribute__((__deprecated__)) +# endif /* GNUC version */ +#endif /* __clang__ || __GNUC__ */ + +#if !defined(ADLMIDI_DEPRECATED) +# define ADLMIDI_DEPRECATED(message) +#endif /* if !defined(ADLMIDI_DEPRECATED) */ + + +#ifdef ADLMIDI_BUILD +# ifndef ADLMIDI_DECLSPEC +# if defined (_WIN32) && defined(ADLMIDI_BUILD_DLL) +# define ADLMIDI_DECLSPEC __declspec(dllexport) +# else +# define ADLMIDI_DECLSPEC +# endif +# endif +#else +# define ADLMIDI_DECLSPEC +#endif + + +/** + * @brief Volume scaling models + */ enum ADLMIDI_VolumeModels { + /*! Automatical choice by the specific bank */ ADLMIDI_VolumeModel_AUTO = 0, + /*! Linearized scaling model, most standard */ ADLMIDI_VolumeModel_Generic = 1, + /*! Native OPL3's logarithmic volume scale */ ADLMIDI_VolumeModel_NativeOPL3 = 2, + /*! Native OPL3's logarithmic volume scale. Alias. */ ADLMIDI_VolumeModel_CMF = ADLMIDI_VolumeModel_NativeOPL3, + /*! Logarithmic volume scale, using volume map table. Used in DMX. */ ADLMIDI_VolumeModel_DMX = 3, + /*! Logarithmic volume scale, used in Apogee Sound System. */ ADLMIDI_VolumeModel_APOGEE = 4, + /*! Aproximated and shorted volume map table. Similar to general, but has less granularity. */ ADLMIDI_VolumeModel_9X = 5 }; +/** + * @brief Sound output format + */ enum ADLMIDI_SampleType { - ADLMIDI_SampleType_S16 = 0, /* signed PCM 16-bit */ - ADLMIDI_SampleType_S8, /* signed PCM 8-bit */ - ADLMIDI_SampleType_F32, /* float 32-bit */ - ADLMIDI_SampleType_F64, /* float 64-bit */ - ADLMIDI_SampleType_S24, /* signed PCM 24-bit */ - ADLMIDI_SampleType_S32, /* signed PCM 32-bit */ - ADLMIDI_SampleType_U8, /* unsigned PCM 8-bit */ - ADLMIDI_SampleType_U16, /* unsigned PCM 16-bit */ - ADLMIDI_SampleType_U24, /* unsigned PCM 24-bit */ - ADLMIDI_SampleType_U32, /* unsigned PCM 32-bit */ - ADLMIDI_SampleType_Count, + /*! signed PCM 16-bit */ + ADLMIDI_SampleType_S16 = 0, + /*! signed PCM 8-bit */ + ADLMIDI_SampleType_S8, + /*! float 32-bit */ + ADLMIDI_SampleType_F32, + /*! float 64-bit */ + ADLMIDI_SampleType_F64, + /*! signed PCM 24-bit */ + ADLMIDI_SampleType_S24, + /*! signed PCM 32-bit */ + ADLMIDI_SampleType_S32, + /*! unsigned PCM 8-bit */ + ADLMIDI_SampleType_U8, + /*! unsigned PCM 16-bit */ + ADLMIDI_SampleType_U16, + /*! unsigned PCM 24-bit */ + ADLMIDI_SampleType_U24, + /*! unsigned PCM 32-bit */ + ADLMIDI_SampleType_U32, + /*! Count of available sample format types */ + ADLMIDI_SampleType_Count }; +/** + * @brief Sound output format context + */ struct ADLMIDI_AudioFormat { - enum ADLMIDI_SampleType type; /* type of sample */ - unsigned containerSize; /* size in bytes of the storage type */ - unsigned sampleOffset; /* distance in bytes between consecutive samples */ + /*! type of sample */ + enum ADLMIDI_SampleType type; + /*! size in bytes of the storage type */ + unsigned containerSize; + /*! distance in bytes between consecutive samples */ + unsigned sampleOffset; }; +/** + * @brief Instance of the library + */ struct ADL_MIDIPlayer { + /*! Private context descriptor */ void *adl_midiPlayer; }; /* DEPRECATED */ #define adl_setNumCards adl_setNumChips -/* Sets number of emulated chips (from 1 to 100). Emulation of multiple chips exchanges polyphony limits*/ -extern int adl_setNumChips(struct ADL_MIDIPlayer *device, int numCards); +/** + * @brief Sets number of emulated chips (from 1 to 100). Emulation of multiple chips extends polyphony limits + * @param device Instance of the library + * @param numChips Count of virtual chips to emulate + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_setNumChips(struct ADL_MIDIPlayer *device, int numChips); -/* Get current number of emulated chips */ -extern int adl_getNumChips(struct ADL_MIDIPlayer *device); +/** + * @brief Get current number of emulated chips + * @param device Instance of the library + * @return Count of working chip emulators + */ +extern ADLMIDI_DECLSPEC int adl_getNumChips(struct ADL_MIDIPlayer *device); -/* Sets a number of the patches bank from 0 to N banks. Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. */ -extern int adl_setBank(struct ADL_MIDIPlayer *device, int bank); +/** + * @brief Get obtained number of emulated chips + * @param device Instance of the library + * @return Count of working chip emulators + */ +extern ADLMIDI_DECLSPEC int adl_getNumChipsObtained(struct ADL_MIDIPlayer *device); -/* Returns total number of available banks */ -extern int adl_getBanksCount(); +/** + * @brief Sets a number of the patches bank from 0 to N banks. + * + * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. + * + * @param device Instance of the library + * @param bank Number of embedded bank + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_setBank(struct ADL_MIDIPlayer *device, int bank); -/* Returns pointer to array of names of every bank */ -extern const char *const *adl_getBankNames(); +/** + * @brief Returns total number of available banks + * @return Total number of available embedded banks + */ +extern ADLMIDI_DECLSPEC int adl_getBanksCount(); -/* Reference to dynamic bank */ +/** + * @brief Returns pointer to array of names of every bank + * @return Array of strings containing the name of every embedded bank + */ +extern ADLMIDI_DECLSPEC const char *const *adl_getBankNames(); + +/** + * @brief Reference to dynamic bank + */ typedef struct ADL_Bank { void *pointer[3]; } ADL_Bank; -/* Identifier of dynamic bank */ +/** + * @brief Identifier of dynamic bank + */ typedef struct ADL_BankId { - ADL_UInt8 percussive, msb, lsb; + /*! 0 if bank is melodic set, or 1 if bank is a percussion set */ + ADL_UInt8 percussive; + /*! Assign to MSB bank number */ + ADL_UInt8 msb; + /*! Assign to LSB bank number */ + ADL_UInt8 lsb; } ADL_BankId; -/* Flags for dynamic bank access */ +/** + * @brief Flags for dynamic bank access + */ enum ADL_BankAccessFlags { - ADLMIDI_Bank_Create = 1, /* create bank, allocating memory as needed */ - ADLMIDI_Bank_CreateRt = 1|2, /* create bank, never allocating memory */ + /*! create bank, allocating memory as needed */ + ADLMIDI_Bank_Create = 1, + /*! create bank, never allocating memory */ + ADLMIDI_Bank_CreateRt = 1|2 }; typedef struct ADL_Instrument ADL_Instrument; -#if defined(ADLMIDI_UNSTABLE_API) -/* Preallocates a minimum number of bank slots. Returns the actual capacity. */ -extern int adl_reserveBanks(struct ADL_MIDIPlayer *device, unsigned banks); -/* Gets the bank designated by the identifier, optionally creating if it does not exist. */ -extern int adl_getBank(struct ADL_MIDIPlayer *device, const ADL_BankId *id, int flags, ADL_Bank *bank); -/* Gets the identifier of a bank. */ -extern int adl_getBankId(struct ADL_MIDIPlayer *device, const ADL_Bank *bank, ADL_BankId *id); -/* Removes a bank. */ -extern int adl_removeBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank); -/* Gets the first bank. */ -extern int adl_getFirstBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank); -/* Iterates to the next bank. */ -extern int adl_getNextBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank); -/* Gets the nth intrument in the bank [0..127]. */ -extern int adl_getInstrument(struct ADL_MIDIPlayer *device, const ADL_Bank *bank, unsigned index, ADL_Instrument *ins); -/* Sets the nth intrument in the bank [0..127]. */ -extern int adl_setInstrument(struct ADL_MIDIPlayer *device, ADL_Bank *bank, unsigned index, const ADL_Instrument *ins); -#endif /* defined(ADLMIDI_UNSTABLE_API) */ - -/*Sets number of 4-operator channels between all chips. - By default, it is automatically re-calculating every bank change. - If you want to specify custom number of four operator channels, - please call this function after bank change (adl_setBank() or adl_openBank()), - otherwise, value will be overwritten by auto-calculated.*/ -extern int adl_setNumFourOpsChn(struct ADL_MIDIPlayer *device, int ops4); - -/*Get current total count of 4-operator channels between all chips*/ -extern int adl_getNumFourOpsChn(struct ADL_MIDIPlayer *device); - -/*Override Enable(1) or Disable(0) AdLib percussion mode. -1 - use bank default AdLib percussion mode*/ -extern void adl_setPercMode(struct ADL_MIDIPlayer *device, int percmod); - -/*Override Enable(1) or Disable(0) deep vibrato state. -1 - use bank default vibrato state*/ -extern void adl_setHVibrato(struct ADL_MIDIPlayer *device, int hvibro); - -/*Override Enable(1) or Disable(0) deep tremolo state. -1 - use bank default tremolo state*/ -extern void adl_setHTremolo(struct ADL_MIDIPlayer *device, int htremo); - -/*Override Enable(1) or Disable(0) scaling of modulator volumes. -1 - use bank default scaling of modulator volumes*/ -extern void adl_setScaleModulators(struct ADL_MIDIPlayer *device, int smod); - -/*Enable(1) or Disable(0) full-range brightness (MIDI CC74 used in XG music to filter result sounding) scaling. - By default, brightness affects sound between 0 and 64. - When this option is enabled, the range will use a full range from 0 up to 127. -*/ -extern void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *device, int fr_brightness); - -/*Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part)*/ -extern void adl_setLoopEnabled(struct ADL_MIDIPlayer *device, int loopEn); - -/* !!!DEPRECATED!!! Enable or disable Logariphmic volume changer */ -extern void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol); - -/*Set different volume range model */ -extern void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel); - -/*Load WOPL bank file from File System. Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time.*/ -extern int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *filePath); - -/*Load WOPL bank file from memory data*/ -extern int adl_openBankData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size); -/* DEPRECATED */ -extern const char *adl_emulatorName(); -/*Returns chip emulator name string*/ -extern const char *adl_chipEmulatorName(struct ADL_MIDIPlayer *device); +/* ======== Setup ======== */ +/** + * @brief Preallocates a minimum number of bank slots. Returns the actual capacity + * @param device Instance of the library + * @param banks Count of bank slots to pre-allocate. + * @return actual capacity of reserved bank slots. + */ +extern ADLMIDI_DECLSPEC int adl_reserveBanks(struct ADL_MIDIPlayer *device, unsigned banks); +/** + * @brief Gets the bank designated by the identifier, optionally creating if it does not exist + * @param device Instance of the library + * @param id Identifier of dynamic bank + * @param flags Flags for dynamic bank access (ADL_BankAccessFlags) + * @param bank Reference to dynamic bank + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_getBank(struct ADL_MIDIPlayer *device, const ADL_BankId *id, int flags, ADL_Bank *bank); +/** + * @brief Gets the identifier of a bank + * @param device Instance of the library + * @param bank Reference to dynamic bank. + * @param id Identifier of dynamic bank + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_getBankId(struct ADL_MIDIPlayer *device, const ADL_Bank *bank, ADL_BankId *id); +/** + * @brief Removes a bank + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_removeBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank); +/** + * @brief Gets the first bank + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_getFirstBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank); +/** + * @brief Iterates to the next bank + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @return 0 on success, <0 when any error has occurred or end has been reached. + */ +extern ADLMIDI_DECLSPEC int adl_getNextBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank); +/** + * @brief Gets the nth intrument in the bank [0..127] + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @param index Index of the instrument + * @param ins Instrument entry + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_getInstrument(struct ADL_MIDIPlayer *device, const ADL_Bank *bank, unsigned index, ADL_Instrument *ins); +/** + * @brief Sets the nth intrument in the bank [0..127] + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @param index Index of the instrument + * @param ins Instrument structure pointer + * @return 0 on success, <0 when any error has occurred + * + * This function allows to override an instrument on the fly + */ +extern ADLMIDI_DECLSPEC int adl_setInstrument(struct ADL_MIDIPlayer *device, ADL_Bank *bank, unsigned index, const ADL_Instrument *ins); +/** + * @brief Loads the melodic or percussive part of the nth embedded bank + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @param num Number of embedded bank to load into the current bank array + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_loadEmbeddedBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank, int num); + + + +/** + * @brief Sets number of 4-operator channels between all chips + * + * By default, it is automatically re-calculating every bank change. + * If you want to specify custom number of four operator channels, + * please call this function after bank change (adl_setBank() or adl_openBank()), + * otherwise, value will be overwritten by auto-calculated. + * If the count is specified as -1, an auto-calculated amount is used instead. + * + * @param device Instance of the library + * @param ops4 Count of four-op channels to allocate between all emulating chips + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_setNumFourOpsChn(struct ADL_MIDIPlayer *device, int ops4); + +/** + * @brief Get current total count of 4-operator channels between all chips + * @param device Instance of the library + * @return 0 on success, <-1 when any error has occurred, but, -1 - "auto" + */ +extern ADLMIDI_DECLSPEC int adl_getNumFourOpsChn(struct ADL_MIDIPlayer *device); + +/** + * @brief Get obtained total count of 4-operator channels between all chips + * @param device Instance of the library + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_getNumFourOpsChnObtained(struct ADL_MIDIPlayer *device); + +/** + * @brief Override Enable(1) or Disable(0) AdLib percussion mode. -1 - use bank default AdLib percussion mode + * + * This function forces rhythm-mode on any bank. The result will work glitchy. + * + * @param device Instance of the library + * @param percmod 0 - disabled, 1 - enabled + */ +extern ADLMIDI_DECLSPEC void adl_setPercMode(struct ADL_MIDIPlayer *device, int percmod); + +/** + * @brief Override Enable(1) or Disable(0) deep vibrato state. -1 - use bank default vibrato state + * @param device Instance of the library + * @param hvibro 0 - disabled, 1 - enabled + */ +extern ADLMIDI_DECLSPEC void adl_setHVibrato(struct ADL_MIDIPlayer *device, int hvibro); + +/** + * @brief Get the deep vibrato state. + * @param device Instance of the library + * @return deep vibrato state on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_getHVibrato(struct ADL_MIDIPlayer *device); + +/** + * @brief Override Enable(1) or Disable(0) deep tremolo state. -1 - use bank default tremolo state + * @param device Instance of the library + * @param htremo 0 - disabled, 1 - enabled + */ +extern ADLMIDI_DECLSPEC void adl_setHTremolo(struct ADL_MIDIPlayer *device, int htremo); + +/** + * @brief Get the deep tremolo state. + * @param device Instance of the library + * @return deep tremolo state on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_getHTremolo(struct ADL_MIDIPlayer *device); + +/** + * @brief Override Enable(1) or Disable(0) scaling of modulator volumes. -1 - use bank default scaling of modulator volumes + * @param device Instance of the library + * @param smod 0 - disabled, 1 - enabled + */ +extern ADLMIDI_DECLSPEC void adl_setScaleModulators(struct ADL_MIDIPlayer *device, int smod); + +/** + * @brief Enable(1) or Disable(0) full-range brightness (MIDI CC74 used in XG music to filter result sounding) scaling + * + * By default, brightness affects sound between 0 and 64. + * When this option is enabled, the brightness will use full range from 0 up to 127. + * + * @param device Instance of the library + * @param fr_brightness 0 - disabled, 1 - enabled + */ +extern ADLMIDI_DECLSPEC void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *device, int fr_brightness); + +/** + * @brief Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part) + * @param device Instance of the library + * @param loopEn 0 - disabled, 1 - enabled + */ +extern ADLMIDI_DECLSPEC void adl_setLoopEnabled(struct ADL_MIDIPlayer *device, int loopEn); + +/** + * @brief Enable or disable soft panning with chip emulators + * @param device Instance of the library + * @param softPanEn 0 - disabled, 1 - enabled + */ +extern ADLMIDI_DECLSPEC void adl_setSoftPanEnabled(struct ADL_MIDIPlayer *device, int softPanEn); + +/** + * @brief [DEPRECATED] Enable or disable Logarithmic volume changer + * + * This function is deprecated. Suggested replacement: `adl_setVolumeRangeModel` with `ADLMIDI_VolumeModel_NativeOPL3` volume model value; + */ +ADLMIDI_DEPRECATED("Use `adl_setVolumeRangeModel(device, ADLMIDI_VolumeModel_NativeOPL3)` instead") +extern ADLMIDI_DECLSPEC void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol); + +/** + * @brief Set different volume range model + * @param device Instance of the library + * @param volumeModel Volume model type (#ADLMIDI_VolumeModels) + */ +extern ADLMIDI_DECLSPEC void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel); + +/** + * @brief Get the volume range model + * @param device Instance of the library + * @return volume model on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_getVolumeRangeModel(struct ADL_MIDIPlayer *device); + +/** + * @brief Load WOPL bank file from File System + * + * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. + * + * @param device Instance of the library + * @param filePath Absolute or relative path to the WOPL bank file. UTF8 encoding is required, even on Windows. + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *filePath); + +/** + * @brief Load WOPL bank file from memory data + * + * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. + * + * @param device Instance of the library + * @param mem Pointer to memory block where is raw data of WOPL bank file is stored + * @param size Size of given memory block + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_openBankData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size); + + +/** + * @brief [DEPRECATED] Dummy function + * + * This function is deprecated. Suggested replacement: `adl_chipEmulatorName` + * + * @return A string that contains a notice to use `adl_chipEmulatorName` instead of this function. + */ +ADLMIDI_DEPRECATED("Use `adl_chipEmulatorName(device)` instead") +extern ADLMIDI_DECLSPEC const char *adl_emulatorName(); + +/** + * @brief Returns chip emulator name string + * @param device Instance of the library + * @return Understandable name of current OPL3 emulator + */ +extern ADLMIDI_DECLSPEC const char *adl_chipEmulatorName(struct ADL_MIDIPlayer *device); + +/** + * @brief List of available OPL3 emulators + */ enum ADL_Emulator { + /*! Nuked OPL3 v. 1.8 */ ADLMIDI_EMU_NUKED = 0, + /*! Nuked OPL3 v. 1.7.4 */ ADLMIDI_EMU_NUKED_174, + /*! DosBox */ ADLMIDI_EMU_DOSBOX, + /*! Count instrument on the level */ ADLMIDI_EMU_end }; -/* Switch the emulation core */ -extern int adl_switchEmulator(struct ADL_MIDIPlayer *device, int emulator); - +/** + * @brief Switch the emulation core + * @param device Instance of the library + * @param emulator Type of emulator (#ADL_Emulator) + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_switchEmulator(struct ADL_MIDIPlayer *device, int emulator); +/** + * @brief Library version context + */ typedef struct { ADL_UInt16 major; ADL_UInt16 minor; ADL_UInt16 patch; } ADL_Version; -/*Run emulator with PCM rate to reduce CPU usage on slow devices. May decrease sounding accuracy.*/ -extern int adl_setRunAtPcmRate(struct ADL_MIDIPlayer *device, int enabled); +/** + * @brief Run emulator with PCM rate to reduce CPU usage on slow devices. + * + * May decrease sounding accuracy on some chip emulators. + * + * @param device Instance of the library + * @param enabled 0 - disabled, 1 - enabled + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_setRunAtPcmRate(struct ADL_MIDIPlayer *device, int enabled); -/*Returns string which contains a version number*/ -extern const char *adl_linkedLibraryVersion(); +/** + * @brief Set 4-bit device identifier. Used by the SysEx processor. + * @param device Instance of the library + * @param id 4-bit device identifier + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_setDeviceIdentifier(struct ADL_MIDIPlayer *device, unsigned id); -/*Returns structure which contains a version number of library */ -extern const ADL_Version *adl_linkedVersion(); +/** + * @section Information + */ -/*Returns string which contains last error message of initialization*/ -extern const char *adl_errorString(); +/** + * @brief Returns string which contains a version number + * @return String which contains a version of the library + */ +extern ADLMIDI_DECLSPEC const char *adl_linkedLibraryVersion(); -/*Returns string which contains last error message on specific device*/ -extern const char *adl_errorInfo(struct ADL_MIDIPlayer *device); +/** + * @brief Returns structure which contains a version number of library + * @return Library version context structure which contains version number of the library + */ +extern ADLMIDI_DECLSPEC const ADL_Version *adl_linkedVersion(); -/*Initialize ADLMIDI Player device*/ -extern struct ADL_MIDIPlayer *adl_init(long sample_rate); -/*Load MIDI file from File System*/ -extern int adl_openFile(struct ADL_MIDIPlayer *device, const char *filePath); +/* ======== Error Info ======== */ -/*Load MIDI file from memory data*/ -extern int adl_openData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size); +/** + * @brief Returns string which contains last error message of initialization + * + * Don't use this function to get info on any function except of `adl_init`! + * Use `adl_errorInfo()` to get error information while workflow + * + * @return String with error message related to library initialization + */ +extern ADLMIDI_DECLSPEC const char *adl_errorString(); -/*Resets MIDI player*/ -extern void adl_reset(struct ADL_MIDIPlayer *device); - -/*Get total time length of current song*/ -extern double adl_totalTimeLength(struct ADL_MIDIPlayer *device); - -/*Get loop start time if presented. -1 means MIDI file has no loop points */ -extern double adl_loopStartTime(struct ADL_MIDIPlayer *device); - -/*Get loop end time if presented. -1 means MIDI file has no loop points */ -extern double adl_loopEndTime(struct ADL_MIDIPlayer *device); - -/*Get current time position in seconds*/ -extern double adl_positionTell(struct ADL_MIDIPlayer *device); - -/*Jump to absolute time position in seconds*/ -extern void adl_positionSeek(struct ADL_MIDIPlayer *device, double seconds); - -/*Reset MIDI track position to begin */ -extern void adl_positionRewind(struct ADL_MIDIPlayer *device); - -/*Set tempo multiplier: 1.0 - original tempo, >1 - play faster, <1 - play slower */ -extern void adl_setTempo(struct ADL_MIDIPlayer *device, double tempo); - -/*Close and delete ADLMIDI device*/ -extern void adl_close(struct ADL_MIDIPlayer *device); +/** + * @brief Returns string which contains last error message on specific device + * @param device Instance of the library + * @return String with error message related to last function call returned non-zero value. + */ +extern ADLMIDI_DECLSPEC const char *adl_errorInfo(struct ADL_MIDIPlayer *device); -/**META**/ +/* ======== Initialization ======== */ -/*Returns string which contains a music title*/ -extern const char *adl_metaMusicTitle(struct ADL_MIDIPlayer *device); +/** + * @brief Initialize ADLMIDI Player device + * + * Tip 1: You can initialize multiple instances and run them in parallel + * Tip 2: Library is NOT thread-safe, therefore don't use same instance in different threads or use mutexes + * Tip 3: Changing of sample rate on the fly is not supported. Re-create the instance again. + * + * @param sample_rate Output sample rate + * @return Instance of the library. If NULL was returned, check the `adl_errorString` message for more info. + */ +extern ADLMIDI_DECLSPEC struct ADL_MIDIPlayer *adl_init(long sample_rate); -/*Returns string which contains a copyright string*/ -extern const char *adl_metaMusicCopyright(struct ADL_MIDIPlayer *device); +/** + * @brief Close and delete ADLMIDI device + * @param device Instance of the library + */ +extern ADLMIDI_DECLSPEC void adl_close(struct ADL_MIDIPlayer *device); -/*Returns count of available track titles: NOTE: there are CAN'T be associated with channel in any of event or note hooks */ -extern size_t adl_metaTrackTitleCount(struct ADL_MIDIPlayer *device); -/*Get track title by index*/ -extern const char *adl_metaTrackTitle(struct ADL_MIDIPlayer *device, size_t index); +/* ======== MIDI Sequencer ======== */ + +/** + * @brief Load MIDI (or any other supported format) file from File System + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param filePath Absolute or relative path to the music file. UTF8 encoding is required, even on Windows. + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_openFile(struct ADL_MIDIPlayer *device, const char *filePath); + +/** + * @brief Load MIDI (or any other supported format) file from memory data + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param mem Pointer to memory block where is raw data of music file is stored + * @param size Size of given memory block + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_openData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size); + +/** + * @brief Resets MIDI player (per-channel setup) into initial state + * @param device Instance of the library + */ +extern ADLMIDI_DECLSPEC void adl_reset(struct ADL_MIDIPlayer *device); + +/** + * @brief Get total time length of current song + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @return Total song length in seconds + */ +extern ADLMIDI_DECLSPEC double adl_totalTimeLength(struct ADL_MIDIPlayer *device); + +/** + * @brief Get loop start time if presented. + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @return Time position in seconds of loop start point, or -1 when file has no loop points + */ +extern ADLMIDI_DECLSPEC double adl_loopStartTime(struct ADL_MIDIPlayer *device); + +/** + * @brief Get loop endtime if presented. + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @return Time position in seconds of loop end point, or -1 when file has no loop points + */ +extern ADLMIDI_DECLSPEC double adl_loopEndTime(struct ADL_MIDIPlayer *device); + +/** + * @brief Get current time position in seconds + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @return Current time position in seconds + */ +extern ADLMIDI_DECLSPEC double adl_positionTell(struct ADL_MIDIPlayer *device); + +/** + * @brief Jump to absolute time position in seconds + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param seconds Destination time position in seconds to seek + */ +extern ADLMIDI_DECLSPEC void adl_positionSeek(struct ADL_MIDIPlayer *device, double seconds); + +/** + * @brief Reset MIDI track position to begin + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + */ +extern ADLMIDI_DECLSPEC void adl_positionRewind(struct ADL_MIDIPlayer *device); + +/** + * @brief Set tempo multiplier + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param tempo Tempo multiplier value: 1.0 - original tempo, >1 - play faster, <1 - play slower + */ +extern ADLMIDI_DECLSPEC void adl_setTempo(struct ADL_MIDIPlayer *device, double tempo); + +/** + * @brief Returns 1 if music position has reached end + * @param device Instance of the library + * @return 1 when end of sing has been reached, otherwise, 0 will be returned. <0 is returned on any error + */ +extern ADLMIDI_DECLSPEC int adl_atEnd(struct ADL_MIDIPlayer *device); + +/** + * @brief Returns the number of tracks of the current sequence + * @param device Instance of the library + * @return Count of tracks in the current sequence + */ +extern ADLMIDI_DECLSPEC size_t adl_trackCount(struct ADL_MIDIPlayer *device); + +/** + * @brief Track options + */ +enum ADLMIDI_TrackOptions +{ + /*! Enabled track */ + ADLMIDI_TrackOption_On = 1, + /*! Disabled track */ + ADLMIDI_TrackOption_Off = 2, + /*! Solo track */ + ADLMIDI_TrackOption_Solo = 3 +}; + +/** + * @brief Sets options on a track of the current sequence + * @param device Instance of the library + * @param trackNumber Identifier of the designated track. + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_setTrackOptions(struct ADL_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions); + +/** + * @brief Handler of callback trigger events + * @param userData Pointer to user data (usually, context of something) + * @param trigger Value of the event which triggered this callback. + * @param track Identifier of the track which triggered this callback. + */ +typedef void (*ADL_TriggerHandler)(void *userData, unsigned trigger, size_t track); + +/** + * @brief Defines a handler for callback trigger events + * @param device Instance of the library + * @param handler Handler to invoke from the sequencer when triggered, or NULL. + * @param userData Instance of the library + * @return 0 on success, <0 when any error has occurred + */ +extern ADLMIDI_DECLSPEC int adl_setTriggerHandler(struct ADL_MIDIPlayer *device, ADL_TriggerHandler handler, void *userData); + + + + +/* ======== Meta-Tags ======== */ + +/** + * @brief Returns string which contains a music title + * @param device Instance of the library + * @return A string that contains music title + */ +extern ADLMIDI_DECLSPEC const char *adl_metaMusicTitle(struct ADL_MIDIPlayer *device); + +/** + * @brief Returns string which contains a copyright string* + * @param device Instance of the library + * @return A string that contains copyright notice, otherwise NULL + */ +extern ADLMIDI_DECLSPEC const char *adl_metaMusicCopyright(struct ADL_MIDIPlayer *device); + +/** + * @brief Returns count of available track titles + * + * NOTE: There are CAN'T be associated with channel in any of event or note hooks + * + * @param device Instance of the library + * @return Count of available MIDI tracks, otherwise NULL + */ +extern ADLMIDI_DECLSPEC size_t adl_metaTrackTitleCount(struct ADL_MIDIPlayer *device); + +/** + * @brief Get track title by index + * @param device Instance of the library + * @param index Index of the track to retreive the title + * @return A string that contains track title, otherwise NULL. + */ +extern ADLMIDI_DECLSPEC const char *adl_metaTrackTitle(struct ADL_MIDIPlayer *device, size_t index); + +/** + * @brief MIDI Marker structure + */ struct Adl_MarkerEntry { + /*! MIDI Marker title */ const char *label; + /*! Absolute time position of the marker in seconds */ double pos_time; + /*! Absolute time position of the marker in MIDI ticks */ unsigned long pos_ticks; }; -/*Returns count of available markers*/ -extern size_t adl_metaMarkerCount(struct ADL_MIDIPlayer *device); +/** + * @brief Returns count of available markers + * @param device Instance of the library + * @return Count of available MIDI markers + */ +extern ADLMIDI_DECLSPEC size_t adl_metaMarkerCount(struct ADL_MIDIPlayer *device); -/*Returns the marker entry*/ -extern struct Adl_MarkerEntry adl_metaMarker(struct ADL_MIDIPlayer *device, size_t index); +/** + * @brief Returns the marker entry + * @param device Instance of the library + * @param index Index of the marker to retreive it. + * @return MIDI Marker description structure. + */ +extern ADLMIDI_DECLSPEC struct Adl_MarkerEntry adl_metaMarker(struct ADL_MIDIPlayer *device, size_t index); -/*Take a sample buffer and iterate MIDI timers */ -extern int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short *out); -/*Take a sample buffer and iterate MIDI timers */ -extern int adl_playFormat(struct ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *left, ADL_UInt8 *right, const struct ADLMIDI_AudioFormat *format); -/*Generate audio output from chip emulators without iteration of MIDI timers.*/ -extern int adl_generate(struct ADL_MIDIPlayer *device, int sampleCount, short *out); +/* ======== Audio output Generation ======== */ -/*Generate audio output from chip emulators without iteration of MIDI timers.*/ -extern int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *left, ADL_UInt8 *right, const struct ADLMIDI_AudioFormat *format); +/** + * @brief Generate PCM signed 16-bit stereo audio output and iterate MIDI timers + * + * Use this function when you are playing MIDI file loaded by `adl_openFile` or by `adl_openData` + * with using of built-in MIDI sequencer. + * + * Don't use count of frames, use instead count of samples. One frame is two samples. + * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param sampleCount Count of samples (not frames!) + * @param out Pointer to output with 16-bit stereo PCM output + * @return Count of given samples, otherwise, 0 or when catching an error while playing + */ +extern ADLMIDI_DECLSPEC int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short *out); + +/** + * @brief Generate PCM stereo audio output in sample format declared by given context and iterate MIDI timers + * + * Use this function when you are playing MIDI file loaded by `adl_openFile` or by `adl_openData` + * with using of built-in MIDI sequencer. + * + * Don't use count of frames, use instead count of samples. One frame is two samples. + * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param sampleCount Count of samples (not frames!) + * @param left Left channel buffer output (Must be casted into bytes array) + * @param right Right channel buffer output (Must be casted into bytes array) + * @param format Destination PCM format format context + * @return Count of given samples, otherwise, 0 or when catching an error while playing + */ +extern ADLMIDI_DECLSPEC int adl_playFormat(struct ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *left, ADL_UInt8 *right, const struct ADLMIDI_AudioFormat *format); + +/** + * @brief Generate PCM signed 16-bit stereo audio output without iteration of MIDI timers + * + * Use this function when you are using library as Real-Time MIDI synthesizer or with + * an external MIDI sequencer. You must to request the amount of samples which is equal + * to the delta between of MIDI event rows. One MIDI row is a group of MIDI events + * are having zero delta/delay between each other. When you are receiving events in + * real time, request the minimal possible delay value. + * + * Don't use count of frames, use instead count of samples. One frame is two samples. + * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! + * + * @param device Instance of the library + * @param sampleCount + * @param out Pointer to output with 16-bit stereo PCM output + * @return Count of given samples, otherwise, 0 or when catching an error while playing + */ +extern ADLMIDI_DECLSPEC int adl_generate(struct ADL_MIDIPlayer *device, int sampleCount, short *out); + +/** + * @brief Generate PCM stereo audio output in sample format declared by given context without iteration of MIDI timers + * + * Use this function when you are using library as Real-Time MIDI synthesizer or with + * an external MIDI sequencer. You must to request the amount of samples which is equal + * to the delta between of MIDI event rows. One MIDI row is a group of MIDI events + * are having zero delta/delay between each other. When you are receiving events in + * real time, request the minimal possible delay value. + * + * Don't use count of frames, use instead count of samples. One frame is two samples. + * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! + * + * @param device Instance of the library + * @param sampleCount + * @param left Left channel buffer output (Must be casted into bytes array) + * @param right Right channel buffer output (Must be casted into bytes array) + * @param format Destination PCM format format context + * @return Count of given samples, otherwise, 0 or when catching an error while playing + */ +extern ADLMIDI_DECLSPEC int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *left, ADL_UInt8 *right, const struct ADLMIDI_AudioFormat *format); /** * @brief Periodic tick handler. - * @param device - * @param seconds seconds since last call - * @param granularity don't expect intervals smaller than this, in seconds - * @return desired number of seconds until next call * - * Use it for Hardware OPL3 mode or when you want to process events differently from adl_play() function. - * DON'T USE IT TOGETHER WITH adl_play()!!! + * Notice: The function is provided to use it with Hardware OPL3 mode or for the purpose to iterate + * MIDI playback without of sound generation. + * + * DON'T USE IT TOGETHER WITH adl_play() and adl_playFormat() calls + * as there are all using this function internally!!! + * + * @param device Instance of the library + * @param seconds Previous delay. On a first moment, pass the `0.0` + * @param granulality Minimal size of one MIDI tick in seconds. + * @return desired number of seconds until next call. Pass this value into `seconds` field in next time */ -extern double adl_tickEvents(struct ADL_MIDIPlayer *device, double seconds, double granuality); - -/*Returns 1 if music position has reached end*/ -extern int adl_atEnd(struct ADL_MIDIPlayer *device); - -/**RealTime**/ - -/*Force Off all notes on all channels*/ -extern void adl_panic(struct ADL_MIDIPlayer *device); - -/*Reset states of all controllers on all MIDI channels*/ -extern void adl_rt_resetState(struct ADL_MIDIPlayer *device); - -/*Turn specific MIDI note ON*/ -extern int adl_rt_noteOn(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 velocity); - -/*Turn specific MIDI note OFF*/ -extern void adl_rt_noteOff(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note); - -/*Set note after-touch*/ -extern void adl_rt_noteAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 atVal); -/*Set channel after-touch*/ -extern void adl_rt_channelAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 atVal); - -/*Apply controller change*/ -extern void adl_rt_controllerChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 type, ADL_UInt8 value); - -/*Apply patch change*/ -extern void adl_rt_patchChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 patch); - -/*Apply pitch bend change*/ -extern void adl_rt_pitchBend(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt16 pitch); -/*Apply pitch bend change*/ -extern void adl_rt_pitchBendML(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb, ADL_UInt8 lsb); - -/*Change LSB of the bank*/ -extern void adl_rt_bankChangeLSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 lsb); -/*Change MSB of the bank*/ -extern void adl_rt_bankChangeMSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb); -/*Change bank by absolute signed value*/ -extern void adl_rt_bankChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_SInt16 bank); +extern ADLMIDI_DECLSPEC double adl_tickEvents(struct ADL_MIDIPlayer *device, double seconds, double granulality); -/**Hooks**/ + +/* ======== Real-Time MIDI ======== */ + +/** + * @brief Force Off all notes on all channels + * @param device Instance of the library + */ +extern ADLMIDI_DECLSPEC void adl_panic(struct ADL_MIDIPlayer *device); + +/** + * @brief Reset states of all controllers on all MIDI channels + * @param device Instance of the library + */ +extern ADLMIDI_DECLSPEC void adl_rt_resetState(struct ADL_MIDIPlayer *device); + +/** + * @brief Turn specific MIDI note ON + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param note Note number to on [Between 0 and 127] + * @param velocity Velocity level [Between 0 and 127] + * @return 1 when note was successfully started, 0 when note was rejected by any reason. + */ +extern ADLMIDI_DECLSPEC int adl_rt_noteOn(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 velocity); + +/** + * @brief Turn specific MIDI note OFF + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param note Note number to off [Between 0 and 127] + */ +extern ADLMIDI_DECLSPEC void adl_rt_noteOff(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note); + +/** + * @brief Set note after-touch + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param note Note number to affect by aftertouch event [Between 0 and 127] + * @param atVal After-Touch value [Between 0 and 127] + */ +extern ADLMIDI_DECLSPEC void adl_rt_noteAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 atVal); + +/** + * @brief Set channel after-touch + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param atVal After-Touch level [Between 0 and 127] + */ +extern ADLMIDI_DECLSPEC void adl_rt_channelAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 atVal); + +/** + * @brief Apply controller change + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param type Type of the controller [Between 0 and 255] + * @param value Value of the controller event [Between 0 and 127] + */ +extern ADLMIDI_DECLSPEC void adl_rt_controllerChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 type, ADL_UInt8 value); + +/** + * @brief Apply patch change + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param patch Patch number [Between 0 and 127] + */ +extern ADLMIDI_DECLSPEC void adl_rt_patchChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 patch); + +/** + * @brief Apply pitch bend change + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param pitch 24-bit pitch bend value + */ +extern ADLMIDI_DECLSPEC void adl_rt_pitchBend(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt16 pitch); + +/** + * @brief Apply pitch bend change + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param msb MSB part of 24-bit pitch bend value + * @param lsb LSB part of 24-bit pitch bend value + */ +extern ADLMIDI_DECLSPEC void adl_rt_pitchBendML(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb, ADL_UInt8 lsb); + +/** + * @brief Change LSB of the bank number (Alias to CC-32 event) + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param lsb LSB value of the MIDI bank number + */ +extern ADLMIDI_DECLSPEC void adl_rt_bankChangeLSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 lsb); + +/** + * @brief Change MSB of the bank (Alias to CC-0 event) + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param msb MSB value of the MIDI bank number + */ +extern ADLMIDI_DECLSPEC void adl_rt_bankChangeMSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb); + +/** + * @brief Change bank by absolute signed value + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param bank Bank number as concoctated signed 16-bit value of MSB and LSB parts. + */ + +extern ADLMIDI_DECLSPEC void adl_rt_bankChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_SInt16 bank); + +/** + * @brief Perform a system exclusive message + * @param device Instance of the library + * @param msg Raw SysEx message buffer (must begin with 0xF0 and end with 0xF7) + * @param size Size of given SysEx message buffer + * @return 1 when SysEx message was successfully processed, 0 when SysEx message was rejected by any reason + */ +extern ADLMIDI_DECLSPEC int adl_rt_systemExclusive(struct ADL_MIDIPlayer *device, const ADL_UInt8 *msg, size_t size); + + + + +/* ======== Hooks and debugging ======== */ + +/** + * @brief Raw event callback + * @param userdata Pointer to user data (usually, context of someting) + * @param type MIDI event type + * @param subtype MIDI event sub-type (special events only) + * @param channel MIDI channel + * @param data Raw event data + * @param len Length of event data + */ typedef void (*ADL_RawEventHook)(void *userdata, ADL_UInt8 type, ADL_UInt8 subtype, ADL_UInt8 channel, const ADL_UInt8 *data, size_t len); + +/** + * @brief Note on/off callback + * @param userdata Pointer to user data (usually, context of someting) + * @param adlchn Chip channel where note was played + * @param note Note number [between 0 and 127] + * @param pressure Velocity level, or -1 when it's note off event + * @param bend Pitch bend offset value + */ typedef void (*ADL_NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend); + +/** + * @brief Debug messages callback + * @param userdata Pointer to user data (usually, context of someting) + * @param fmt Format strign output (in context of `printf()` standard function) + */ typedef void (*ADL_DebugMessageHook)(void *userdata, const char *fmt, ...); -/* Set raw MIDI event hook */ -extern void adl_setRawEventHook(struct ADL_MIDIPlayer *device, ADL_RawEventHook rawEventHook, void *userData); +/** + * @brief Set raw MIDI event hook + * @param device Instance of the library + * @param rawEventHook Pointer to the callback function which will be called on every MIDI event + * @param userData Pointer to user data which will be passed through the callback. + */ +extern ADLMIDI_DECLSPEC void adl_setRawEventHook(struct ADL_MIDIPlayer *device, ADL_RawEventHook rawEventHook, void *userData); -/* Set note hook */ -extern void adl_setNoteHook(struct ADL_MIDIPlayer *device, ADL_NoteHook noteHook, void *userData); +/** + * @brief Set note hook + * @param device Instance of the library + * @param noteHook Pointer to the callback function which will be called on every noteOn MIDI event + * @param userData Pointer to user data which will be passed through the callback. + */ +extern ADLMIDI_DECLSPEC void adl_setNoteHook(struct ADL_MIDIPlayer *device, ADL_NoteHook noteHook, void *userData); -/* Set debug message hook */ -extern void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_DebugMessageHook debugMessageHook, void *userData); +/** + * @brief Set debug message hook + * @param device Instance of the library + * @param debugMessageHook Pointer to the callback function which will be called on every debug message + * @param userData Pointer to user data which will be passed through the callback. + */ +extern ADLMIDI_DECLSPEC void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_DebugMessageHook debugMessageHook, void *userData); + +/** + * @brief Get a textual description of the channel state. For display only. + * @param device Instance of the library + * @param text Destination char buffer for channel usage state. Every entry is assigned to the chip channel. + * @param attr Destination char buffer for additional attributes like MIDI channel number that uses this chip channel. + * @param size Size of given buffers (both text and attr are must have same size!) + * @return 0 on success, <0 when any error has occurred + * + * Every character in the `text` buffer means the type of usage: + * ``` + * `-` - channel is unused (free) + * `+` - channel is used by two-operator voice + * `#` - channel is used by four-operator voice + * `@` - channel is used to play automatic arpeggio on chip channels overflow + * `r` - rhythm-mode channel note + * ``` + * + * The `attr` field receives the MIDI channel from which the chip channel is used. + * To get the valid MIDI channel you will need to apply the & 0x0F mask to every value. + */ +extern ADLMIDI_DECLSPEC int adl_describeChannels(struct ADL_MIDIPlayer *device, char *text, char *attr, size_t size); -/**Instrument structures**/ + +/* ======== Instrument structures ======== */ + +/** + * @brief Version of the instrument data format + */ enum { - ADLMIDI_InstrumentVersion = 0, + ADLMIDI_InstrumentVersion = 0 }; +/** + * @brief Instrument flags + */ typedef enum ADL_InstrumentFlags { - /* Is two-operator single-voice instrument (no flags) */ + /*! Is two-operator single-voice instrument (no flags) */ ADLMIDI_Ins_2op = 0x00, - /* Is true four-operator instrument */ + /*! Is true four-operator instrument */ ADLMIDI_Ins_4op = 0x01, - /* Is pseudo four-operator (two 2-operator voices) instrument */ + /*! Is pseudo four-operator (two 2-operator voices) instrument */ ADLMIDI_Ins_Pseudo4op = 0x02, - /* Is a blank instrument entry */ + /*! Is a blank instrument entry */ ADLMIDI_Ins_IsBlank = 0x04, - /* Mask of the flags range */ - ADLMIDI_Ins_ALL_MASK = 0x07, + + /*! RythmMode flags mask */ + ADLMIDI_Ins_RhythmModeMask = 0x38, + + /*! Mask of the flags range */ + ADLMIDI_Ins_ALL_MASK = 0x07 } ADL_InstrumentFlags; +/** + * @brief Rhythm-mode drum type + */ +typedef enum ADL_RhythmMode +{ + /*! RythmMode: BassDrum */ + ADLMIDI_RM_BassDrum = 0x08, + /*! RythmMode: Snare */ + ADLMIDI_RM_Snare = 0x10, + /*! RythmMode: TomTom */ + ADLMIDI_RM_TomTom = 0x18, + /*! RythmMode: Cymbal */ + ADLMIDI_RM_Cymbal = 0x20, + /*! RythmMode: HiHat */ + ADLMIDI_RM_HiHat = 0x28 +} ADL_RhythmMode; + + +/** + * @brief Operator structure, part of Instrument structure + */ typedef struct ADL_Operator { - /* AM/Vib/Env/Ksr/FMult characteristics */ + /*! AM/Vib/Env/Ksr/FMult characteristics */ ADL_UInt8 avekf_20; - /* Key Scale Level / Total level register data */ + /*! Key Scale Level / Total level register data */ ADL_UInt8 ksl_l_40; - /* Attack / Decay */ + /*! Attack / Decay */ ADL_UInt8 atdec_60; - /* Systain and Release register data */ + /*! Systain and Release register data */ ADL_UInt8 susrel_80; - /* Wave form */ + /*! Wave form */ ADL_UInt8 waveform_E0; } ADL_Operator; +/** + * @brief Instrument structure + */ typedef struct ADL_Instrument { - /* Version of the instrument object */ + /*! Version of the instrument object */ int version; - /* MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */ + /*! MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */ ADL_SInt16 note_offset1; - /* MIDI note key (half-tone) offset for a second voice in pseudo-4-op mode */ + /*! MIDI note key (half-tone) offset for a second voice in pseudo-4-op mode */ ADL_SInt16 note_offset2; - /* MIDI note velocity offset (taken from Apogee TMB format) */ + /*! MIDI note velocity offset (taken from Apogee TMB format) */ ADL_SInt8 midi_velocity_offset; - /* Second voice detune level (taken from DMX OP2) */ + /*! Second voice detune level (taken from DMX OP2) */ ADL_SInt8 second_voice_detune; - /* Percussion MIDI base tone number at which this drum will be played */ + /*! Percussion MIDI base tone number at which this drum will be played */ ADL_UInt8 percussion_key_number; - /* Enum ADL_InstrumentFlags */ + /** + * @var inst_flags + * @brief Instrument flags + * + * Enums: #ADL_InstrumentFlags and #ADL_RhythmMode + * + * Bitwise flags bit map: + * ``` + * [0EEEDCBA] + * A) 0x00 - 2-operator mode + * B) 0x01 - 4-operator mode + * C) 0x02 - pseudo-4-operator (two 2-operator voices) mode + * D) 0x04 - is 'blank' instrument (instrument which has no sound) + * E) 0x38 - Reserved for rhythm-mode percussion type number (three bits number) + * -> 0x00 - Melodic or Generic drum (rhythm-mode is disabled) + * -> 0x08 - is Bass drum + * -> 0x10 - is Snare + * -> 0x18 - is Tom-tom + * -> 0x20 - is Cymbal + * -> 0x28 - is Hi-hat + * 0) Reserved / Unused + * ``` + */ ADL_UInt8 inst_flags; - /* Feedback&Connection register for first and second operators */ + /*! Feedback&Connection register for first and second operators */ ADL_UInt8 fb_conn1_C0; - /* Feedback&Connection register for third and fourth operators */ + /*! Feedback&Connection register for third and fourth operators */ ADL_UInt8 fb_conn2_C0; - /* Operators register data */ + /*! Operators register data */ ADL_Operator operators[4]; - /* Millisecond delay of sounding while key is on */ + /*! Millisecond delay of sounding while key is on */ ADL_UInt16 delay_on_ms; - /* Millisecond delay of sounding after key off */ + /*! Millisecond delay of sounding after key off */ ADL_UInt16 delay_off_ms; } ADL_Instrument; diff --git a/src/sound/adlmidi/adlmidi.hpp b/src/sound/adlmidi/adlmidi.hpp index 6d01b8d33..f2cd59d27 100644 --- a/src/sound/adlmidi/adlmidi.hpp +++ b/src/sound/adlmidi/adlmidi.hpp @@ -24,9 +24,11 @@ #ifndef ADLMIDI_HPP #define ADLMIDI_HPP +#include "adlmidi.h" + struct ADL_MIDIPlayer; -class AdlInstrumentTester +class ADLMIDI_DECLSPEC AdlInstrumentTester { struct Impl; Impl *P; diff --git a/src/sound/adlmidi/adlmidi_bankmap.h b/src/sound/adlmidi/adlmidi_bankmap.h index e4534cd6e..5d747d1b3 100644 --- a/src/sound/adlmidi/adlmidi_bankmap.h +++ b/src/sound/adlmidi/adlmidi_bankmap.h @@ -40,7 +40,7 @@ template class BasicBankMap { public: - typedef uint16_t key_type; /* the bank identifier */ + typedef size_t key_type; /* the bank identifier */ typedef T mapped_type; typedef std::pair value_type; @@ -74,7 +74,7 @@ private: enum { hash_bits = 8, /* worst case # of collisions: 128^2/2^hash_bits */ - hash_buckets = 1 << hash_bits, + hash_buckets = 1 << hash_bits }; public: diff --git a/src/sound/adlmidi/adlmidi_bankmap.tcc b/src/sound/adlmidi/adlmidi_bankmap.tcc index 76e70016c..90d88949b 100644 --- a/src/sound/adlmidi/adlmidi_bankmap.tcc +++ b/src/sound/adlmidi/adlmidi_bankmap.tcc @@ -37,7 +37,7 @@ template inline size_t BasicBankMap::hash(key_type key) { // disregard the 0 high bit in LSB - key = (key & 127) | ((key >> 8) << 7); + key = key_type(key & 127) | key_type((key >> 8) << 7); // take low part as hash value return key & (hash_buckets - 1); } diff --git a/src/sound/adlmidi/adlmidi_cvt.hpp b/src/sound/adlmidi/adlmidi_cvt.hpp new file mode 100644 index 000000000..449fe2ffd --- /dev/null +++ b/src/sound/adlmidi/adlmidi_cvt.hpp @@ -0,0 +1,124 @@ +/* + * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation + * + * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma + * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov + * + * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: + * http://iki.fi/bisqwit/source/adlmidi.html + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "adldata.hh" +#include "wopl/wopl_file.h" +#include + +template +static void cvt_generic_to_FMIns(adlinsdata2 &ins, const WOPLI &in) +{ + ins.voice2_fine_tune = 0.0; + int8_t voice2_fine_tune = in.second_voice_detune; + if(voice2_fine_tune != 0) + { + if(voice2_fine_tune == 1) + ins.voice2_fine_tune = 0.000025; + else if(voice2_fine_tune == -1) + ins.voice2_fine_tune = -0.000025; + else + ins.voice2_fine_tune = voice2_fine_tune * (15.625 / 1000.0); + } + + ins.midi_velocity_offset = in.midi_velocity_offset; + ins.tone = in.percussion_key_number; + ins.flags = (in.inst_flags & WOPL_Ins_4op) && (in.inst_flags & WOPL_Ins_Pseudo4op) ? adlinsdata::Flag_Pseudo4op : 0; + ins.flags|= (in.inst_flags & WOPL_Ins_4op) && ((in.inst_flags & WOPL_Ins_Pseudo4op) == 0) ? adlinsdata::Flag_Real4op : 0; + ins.flags|= (in.inst_flags & WOPL_Ins_IsBlank) ? adlinsdata::Flag_NoSound : 0; + ins.flags|= in.inst_flags & WOPL_RhythmModeMask; + + for(size_t op = 0, slt = 0; op < 4; op++, slt++) + { + ins.adl[slt].carrier_E862 = + ((static_cast(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm + | ((static_cast(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel + | ((static_cast(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec + | ((static_cast(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM + ins.adl[slt].carrier_40 = in.operators[op].ksl_l_40;//KSLL + + op++; + ins.adl[slt].modulator_E862 = + ((static_cast(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm + | ((static_cast(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel + | ((static_cast(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec + | ((static_cast(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM + ins.adl[slt].modulator_40 = in.operators[op].ksl_l_40;//KSLL + } + + ins.adl[0].finetune = static_cast(in.note_offset1); + ins.adl[0].feedconn = in.fb_conn1_C0; + ins.adl[1].finetune = static_cast(in.note_offset2); + ins.adl[1].feedconn = in.fb_conn2_C0; + + ins.ms_sound_kon = in.delay_on_ms; + ins.ms_sound_koff = in.delay_off_ms; +} + +template +static void cvt_FMIns_to_generic(WOPLI &ins, const adlinsdata2 &in) +{ + ins.second_voice_detune = 0; + double voice2_fine_tune = in.voice2_fine_tune; + if(voice2_fine_tune != 0) + { + if(voice2_fine_tune > 0 && voice2_fine_tune <= 0.000025) + ins.second_voice_detune = 1; + else if(voice2_fine_tune < 0 && voice2_fine_tune >= -0.000025) + ins.second_voice_detune = -1; + else + { + long value = static_cast(round(voice2_fine_tune * (1000.0 / 15.625))); + value = (value < -128) ? -128 : value; + value = (value > +127) ? +127 : value; + ins.second_voice_detune = static_cast(value); + } + } + + ins.midi_velocity_offset = in.midi_velocity_offset; + ins.percussion_key_number = in.tone; + ins.inst_flags = (in.flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)) ? WOPL_Ins_4op : 0; + ins.inst_flags|= (in.flags & adlinsdata::Flag_Pseudo4op) ? WOPL_Ins_Pseudo4op : 0; + ins.inst_flags|= (in.flags & adlinsdata::Flag_NoSound) ? WOPL_Ins_IsBlank : 0; + ins.inst_flags |= in.flags & adlinsdata::Mask_RhythmMode; + + for(size_t op = 0; op < 4; op++) + { + const adldata &in2op = in.adl[(op < 2) ? 0 : 1]; + uint32_t regE862 = ((op & 1) == 0) ? in2op.carrier_E862 : in2op.modulator_E862; + uint8_t reg40 = ((op & 1) == 0) ? in2op.carrier_40 : in2op.modulator_40; + + ins.operators[op].waveform_E0 = static_cast(regE862 >> 24); + ins.operators[op].susrel_80 = static_cast(regE862 >> 16); + ins.operators[op].atdec_60 = static_cast(regE862 >> 8); + ins.operators[op].avekf_20 = static_cast(regE862 >> 0); + ins.operators[op].ksl_l_40 = reg40; + } + + ins.note_offset1 = in.adl[0].finetune; + ins.fb_conn1_C0 = in.adl[0].feedconn; + ins.note_offset2 = in.adl[1].finetune; + ins.fb_conn2_C0 = in.adl[1].feedconn; + + ins.delay_on_ms = in.ms_sound_kon; + ins.delay_off_ms = in.ms_sound_koff; +} diff --git a/src/sound/adlmidi/adlmidi_load.cpp b/src/sound/adlmidi/adlmidi_load.cpp index 7f69e259f..07ad87573 100644 --- a/src/sound/adlmidi/adlmidi_load.cpp +++ b/src/sound/adlmidi/adlmidi_load.cpp @@ -1,4 +1,4 @@ -/* +/* * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation * * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma @@ -22,168 +22,23 @@ */ #include "adlmidi_private.hpp" +#include "adlmidi_cvt.hpp" #include "wopl/wopl_file.h" -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -# ifndef ADLMIDI_DISABLE_MUS_SUPPORT -# include "adlmidi_mus2mid.h" -# endif//MUS -# ifndef ADLMIDI_DISABLE_XMI_SUPPORT -# include "adlmidi_xmi2mid.h" -# endif//XMI -#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -uint64_t MIDIplay::ReadBEint(const void *buffer, size_t nbytes) -{ - uint64_t result = 0; - const unsigned char *data = reinterpret_cast(buffer); - - for(unsigned n = 0; n < nbytes; ++n) - result = (result << 8) + data[n]; - - return result; -} - -uint64_t MIDIplay::ReadLEint(const void *buffer, size_t nbytes) -{ - uint64_t result = 0; - const unsigned char *data = reinterpret_cast(buffer); - - for(unsigned n = 0; n < nbytes; ++n) - result = result + static_cast(data[n] << (n * 8)); - - return result; -} - -#endif - bool MIDIplay::LoadBank(const std::string &filename) { - fileReader file; + FileAndMemReader file; file.openFile(filename.c_str()); return LoadBank(file); } bool MIDIplay::LoadBank(const void *data, size_t size) { - fileReader file; + FileAndMemReader file; file.openData(data, size); return LoadBank(file); } -template -static void cvt_generic_to_FMIns(adlinsdata2 &ins, const WOPLI &in) -{ - ins.voice2_fine_tune = 0.0; - int8_t voice2_fine_tune = in.second_voice_detune; - if(voice2_fine_tune != 0) - { - if(voice2_fine_tune == 1) - ins.voice2_fine_tune = 0.000025; - else if(voice2_fine_tune == -1) - ins.voice2_fine_tune = -0.000025; - else - ins.voice2_fine_tune = voice2_fine_tune * (15.625 / 1000.0); - } - - ins.tone = in.percussion_key_number; - ins.flags = (in.inst_flags & WOPL_Ins_4op) && (in.inst_flags & WOPL_Ins_Pseudo4op) ? adlinsdata::Flag_Pseudo4op : 0; - ins.flags|= (in.inst_flags & WOPL_Ins_4op) && ((in.inst_flags & WOPL_Ins_Pseudo4op) == 0) ? adlinsdata::Flag_Real4op : 0; - ins.flags|= (in.inst_flags & WOPL_Ins_IsBlank) ? adlinsdata::Flag_NoSound : 0; - - bool fourOps = (in.inst_flags & WOPL_Ins_4op) || (in.inst_flags & WOPL_Ins_Pseudo4op); - for(size_t op = 0, slt = 0; op < static_cast(fourOps ? 4 : 2); op++, slt++) - { - ins.adl[slt].carrier_E862 = - ((static_cast(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm - | ((static_cast(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel - | ((static_cast(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec - | ((static_cast(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM - ins.adl[slt].carrier_40 = in.operators[op].ksl_l_40;//KSLL - - op++; - ins.adl[slt].modulator_E862 = - ((static_cast(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm - | ((static_cast(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel - | ((static_cast(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec - | ((static_cast(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM - ins.adl[slt].modulator_40 = in.operators[op].ksl_l_40;//KSLL - } - - ins.adl[0].finetune = static_cast(in.note_offset1); - ins.adl[0].feedconn = in.fb_conn1_C0; - if(!fourOps) - ins.adl[1] = ins.adl[0]; - else - { - ins.adl[1].finetune = static_cast(in.note_offset2); - ins.adl[1].feedconn = in.fb_conn2_C0; - } - - ins.ms_sound_kon = in.delay_on_ms; - ins.ms_sound_koff = in.delay_off_ms; -} - -template -static void cvt_FMIns_to_generic(WOPLI &ins, const adlinsdata2 &in) -{ - ins.second_voice_detune = 0; - double voice2_fine_tune = in.voice2_fine_tune; - if(voice2_fine_tune != 0) - { - if(voice2_fine_tune > 0 && voice2_fine_tune <= 0.000025) - ins.second_voice_detune = 1; - else if(voice2_fine_tune < 0 && voice2_fine_tune >= -0.000025) - ins.second_voice_detune = -1; - else - { - long value = lround(voice2_fine_tune * (1000.0 / 15.625)); - value = (value < -128) ? -128 : value; - value = (value > +127) ? +127 : value; - ins.second_voice_detune = static_cast(value); - } - } - - ins.percussion_key_number = in.tone; - bool fourOps = (in.flags & adlinsdata::Flag_Pseudo4op) || in.adl[0] != in.adl[1]; - ins.inst_flags = fourOps ? WOPL_Ins_4op : 0; - ins.inst_flags|= (in.flags & adlinsdata::Flag_Pseudo4op) ? WOPL_Ins_Pseudo4op : 0; - ins.inst_flags|= (in.flags & adlinsdata::Flag_NoSound) ? WOPL_Ins_IsBlank : 0; - - for(size_t op = 0, slt = 0; op < static_cast(fourOps ? 4 : 2); op++, slt++) - { - ins.operators[op].waveform_E0 = static_cast(in.adl[slt].carrier_E862 >> 24); - ins.operators[op].susrel_80 = static_cast(in.adl[slt].carrier_E862 >> 16); - ins.operators[op].atdec_60 = static_cast(in.adl[slt].carrier_E862 >> 8); - ins.operators[op].avekf_20 = static_cast(in.adl[slt].carrier_E862 >> 0); - ins.operators[op].ksl_l_40 = in.adl[slt].carrier_40; - - op++; - ins.operators[op].waveform_E0 = static_cast(in.adl[slt].carrier_E862 >> 24); - ins.operators[op].susrel_80 = static_cast(in.adl[slt].carrier_E862 >> 16); - ins.operators[op].atdec_60 = static_cast(in.adl[slt].carrier_E862 >> 8); - ins.operators[op].avekf_20 = static_cast(in.adl[slt].carrier_E862 >> 0); - ins.operators[op].ksl_l_40 = in.adl[slt].carrier_40; - } - - ins.note_offset1 = in.adl[0].finetune; - ins.fb_conn1_C0 = in.adl[0].feedconn; - if(!fourOps) - { - ins.operators[2] = ins.operators[0]; - ins.operators[3] = ins.operators[1]; - } - else - { - ins.note_offset2 = in.adl[1].finetune; - ins.fb_conn2_C0 = in.adl[1].feedconn; - } - - ins.delay_on_ms = in.ms_sound_kon; - ins.delay_off_ms = in.ms_sound_koff; -} - void cvt_ADLI_to_FMIns(adlinsdata2 &ins, const ADL_Instrument &in) { return cvt_generic_to_FMIns(ins, in); @@ -194,7 +49,7 @@ void cvt_FMIns_to_ADLI(ADL_Instrument &ins, const adlinsdata2 &in) cvt_FMIns_to_generic(ins, in); } -bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) +bool MIDIplay::LoadBank(FileAndMemReader &fr) { int err = 0; WOPLFile *wopl = NULL; @@ -207,9 +62,8 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) } // Read complete bank file into the memory - fr.seek(0, SEEK_END); - fsize = fr.tell(); - fr.seek(0, SEEK_SET); + fsize = fr.fileSize(); + fr.seek(0, FileAndMemReader::SET); // Allocate necessary memory block raw_file_data = (char*)malloc(fsize); if(!raw_file_data) @@ -250,29 +104,28 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) } } - opl.dynamic_bank_setup.adLibPercussions = false; - opl.dynamic_bank_setup.scaleModulators = false; - opl.dynamic_bank_setup.deepTremolo = (wopl->opl_flags & WOPL_FLAG_DEEP_TREMOLO) != 0; - opl.dynamic_bank_setup.deepVibrato = (wopl->opl_flags & WOPL_FLAG_DEEP_VIBRATO) != 0; - opl.dynamic_bank_setup.volumeModel = wopl->volume_model; - m_setup.HighTremoloMode = -1; - m_setup.HighVibratoMode = -1; - m_setup.VolumeModel = ADLMIDI_VolumeModel_AUTO; + m_synth.m_insBankSetup.adLibPercussions = false; + m_synth.m_insBankSetup.scaleModulators = false; + m_synth.m_insBankSetup.deepTremolo = (wopl->opl_flags & WOPL_FLAG_DEEP_TREMOLO) != 0; + m_synth.m_insBankSetup.deepVibrato = (wopl->opl_flags & WOPL_FLAG_DEEP_VIBRATO) != 0; + m_synth.m_insBankSetup.volumeModel = wopl->volume_model; + m_setup.deepTremoloMode = -1; + m_setup.deepVibratoMode = -1; + m_setup.volumeScaleModel = ADLMIDI_VolumeModel_AUTO; - opl.setEmbeddedBank(m_setup.AdlBank); + m_synth.setEmbeddedBank(m_setup.bankId); uint16_t slots_counts[2] = {wopl->banks_count_melodic, wopl->banks_count_percussion}; WOPLBank *slots_src_ins[2] = { wopl->banks_melodic, wopl->banks_percussive }; - for(unsigned ss = 0; ss < 2; ss++) + for(size_t ss = 0; ss < 2; ss++) { - for(unsigned i = 0; i < slots_counts[ss]; i++) + for(size_t i = 0; i < slots_counts[ss]; i++) { - unsigned bankno = - (slots_src_ins[ss][i].bank_midi_msb * 256) + - slots_src_ins[ss][i].bank_midi_lsb + - (ss ? OPL3::PercussionTag : 0); - OPL3::Bank &bank = opl.dynamic_banks[bankno]; + size_t bankno = (slots_src_ins[ss][i].bank_midi_msb * 256) + + (slots_src_ins[ss][i].bank_midi_lsb) + + (ss ? size_t(OPL3::PercussionTag) : 0); + OPL3::Bank &bank = m_synth.m_insBanks[bankno]; for(int j = 0; j < 128; j++) { adlinsdata2 &ins = bank.ins[j]; @@ -283,7 +136,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) } } - opl.AdlBank = ~0u; // Use dynamic banks! + m_synth.m_embeddedBank = OPL3::CustomBankTag; // Use dynamic banks! //Percussion offset is count of instruments multipled to count of melodic banks applySetup(); @@ -293,189 +146,45 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) } #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -bool MIDIplay::LoadMIDI(const std::string &filename) -{ - fileReader file; - file.openFile(filename.c_str()); - if(!LoadMIDI(file)) - return false; - return true; -} -bool MIDIplay::LoadMIDI(const void *data, size_t size) +bool MIDIplay::LoadMIDI_pre() { - fileReader file; - file.openData(data, size); - return LoadMIDI(file); -} - -bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr) -{ - size_t fsize; - ADL_UNUSED(fsize); - //! Temp buffer for conversion - AdlMIDI_CPtr cvt_buf; - errorString.clear(); - - #ifdef DISABLE_EMBEDDED_BANKS - if((opl.AdlBank != ~0u) || opl.dynamic_banks.empty()) +#ifdef DISABLE_EMBEDDED_BANKS + if((m_synth.m_embeddedBank != OPL3::CustomBankTag) || m_synth.m_insBanks.empty()) { errorStringOut = "Bank is not set! Please load any instruments bank by using of adl_openBankFile() or adl_openBankData() functions!"; return false; } - #endif - - if(!fr.isValid()) - { - errorStringOut = "Invalid data stream!\n"; - #ifndef _WIN32 - errorStringOut += std::strerror(errno); - #endif - return false; - } - +#endif /**** Set all properties BEFORE starting of actial file reading! ****/ + resetMIDI(); applySetup(); - atEnd = false; - loopStart = true; - invalidLoop = false; + return true; +} - bool is_GMF = false; // GMD/MUS files (ScummVM) - //bool is_MUS = false; // MUS/DMX files (Doom) - bool is_IMF = false; // IMF - bool is_CMF = false; // Creative Music format (CMF/CTMF) - bool is_RSXX = false; // RSXX, such as Cartooners - - const size_t HeaderSize = 4 + 4 + 2 + 2 + 2; // 14 - char HeaderBuf[HeaderSize] = ""; - size_t DeltaTicks = 192, TrackCount = 1; - -riffskip: - fsize = fr.read(HeaderBuf, 1, HeaderSize); - - if(std::memcmp(HeaderBuf, "RIFF", 4) == 0) +bool MIDIplay::LoadMIDI_post() +{ + MidiSequencer::FileFormat format = m_sequencer.getFormat(); + if(format == MidiSequencer::Format_CMF) { - fr.seek(6l, SEEK_CUR); - goto riffskip; - } + const std::vector &instruments = m_sequencer.getRawCmfInstruments(); + m_synth.m_insBanks.clear();//Clean up old banks - if(std::memcmp(HeaderBuf, "GMF\x1", 4) == 0) - { - // GMD/MUS files (ScummVM) - fr.seek(7 - static_cast(HeaderSize), SEEK_CUR); - is_GMF = true; - } - #ifndef ADLMIDI_DISABLE_MUS_SUPPORT - else if(std::memcmp(HeaderBuf, "MUS\x1A", 4) == 0) - { - // MUS/DMX files (Doom) - fr.seek(0, SEEK_END); - size_t mus_len = fr.tell(); - fr.seek(0, SEEK_SET); - uint8_t *mus = (uint8_t *)malloc(mus_len); - if(!mus) + uint16_t ins_count = static_cast(instruments.size()); + for(uint16_t i = 0; i < ins_count; ++i) { - errorStringOut = "Out of memory!"; - return false; - } - fr.read(mus, 1, mus_len); - //Close source stream - fr.close(); - - uint8_t *mid = NULL; - uint32_t mid_len = 0; - int m2mret = AdlMidi_mus2midi(mus, static_cast(mus_len), - &mid, &mid_len, 0); - if(mus) free(mus); - if(m2mret < 0) - { - errorStringOut = "Invalid MUS/DMX data format!"; - return false; - } - cvt_buf.reset(mid); - //Open converted MIDI file - fr.openData(mid, static_cast(mid_len)); - //Re-Read header again! - goto riffskip; - } - #endif //ADLMIDI_DISABLE_MUS_SUPPORT - #ifndef ADLMIDI_DISABLE_XMI_SUPPORT - else if(std::memcmp(HeaderBuf, "FORM", 4) == 0) - { - if(std::memcmp(HeaderBuf + 8, "XDIR", 4) != 0) - { - fr.close(); - errorStringOut = fr._fileName + ": Invalid format\n"; - return false; - } - - fr.seek(0, SEEK_END); - size_t mus_len = fr.tell(); - fr.seek(0, SEEK_SET); - uint8_t *mus = (uint8_t*)malloc(mus_len); - if(!mus) - { - errorStringOut = "Out of memory!"; - return false; - } - fr.read(mus, 1, mus_len); - //Close source stream - fr.close(); - - uint8_t *mid = NULL; - uint32_t mid_len = 0; - int m2mret = AdlMidi_xmi2midi(mus, static_cast(mus_len), - &mid, &mid_len, XMIDI_CONVERT_NOCONVERSION); - if(mus) free(mus); - if(m2mret < 0) - { - errorStringOut = "Invalid XMI data format!"; - return false; - } - cvt_buf.reset(mid); - //Open converted MIDI file - fr.openData(mid, static_cast(mid_len)); - //Re-Read header again! - goto riffskip; - } - #endif //ADLMIDI_DISABLE_XMI_SUPPORT - else if(std::memcmp(HeaderBuf, "CTMF", 4) == 0) - { - opl.dynamic_banks.clear(); - // Creative Music Format (CMF). - // When playing CTMF files, use the following commandline: - // adlmidi song8.ctmf -p -v 1 1 0 - // i.e. enable percussion mode, deeper vibrato, and use only 1 card. - is_CMF = true; - //unsigned version = ReadLEint(HeaderBuf+4, 2); - uint64_t ins_start = ReadLEint(HeaderBuf + 6, 2); - uint64_t mus_start = ReadLEint(HeaderBuf + 8, 2); - //unsigned deltas = ReadLEint(HeaderBuf+10, 2); - uint64_t ticks = ReadLEint(HeaderBuf + 12, 2); - // Read title, author, remarks start offsets in file - fr.read(HeaderBuf, 1, 6); - //unsigned long notes_starts[3] = {ReadLEint(HeaderBuf+0,2),ReadLEint(HeaderBuf+0,4),ReadLEint(HeaderBuf+0,6)}; - fr.seek(16, SEEK_CUR); // Skip the channels-in-use table - fr.read(HeaderBuf, 1, 4); - uint64_t ins_count = ReadLEint(HeaderBuf + 0, 2); //, basictempo = ReadLEint(HeaderBuf+2, 2); - fr.seek(static_cast(ins_start), SEEK_SET); - - //std::printf("%u instruments\n", ins_count); - for(unsigned i = 0; i < ins_count; ++i) - { - unsigned bank = i / 256; - bank = (bank & 127) + ((bank >> 7) << 8); + const uint8_t *InsData = instruments[i].data; + size_t bank = i / 256; + bank = ((bank & 127) + ((bank >> 7) << 8)); if(bank > 127 + (127 << 8)) break; - bank += (i % 256 < 128) ? 0 : OPL3::PercussionTag; + bank += (i % 256 < 128) ? 0 : size_t(OPL3::PercussionTag); - unsigned char InsData[16]; - fr.read(InsData, 1, 16); /*std::printf("Ins %3u: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", i, InsData[0],InsData[1],InsData[2],InsData[3], InsData[4],InsData[5],InsData[6],InsData[7], InsData[8],InsData[9],InsData[10],InsData[11], InsData[12],InsData[13],InsData[14],InsData[15]);*/ - adlinsdata2 &adlins = opl.dynamic_banks[bank].ins[i % 128]; + adlinsdata2 &adlins = m_synth.m_insBanks[bank].ins[i % 128]; adldata adl; adl.modulator_E862 = ((static_cast(InsData[8] & 0x07) << 24) & 0xFF000000) //WaveForm @@ -500,224 +209,79 @@ riffskip: adlins.voice2_fine_tune = 0.0; } - fr.seeku(mus_start, SEEK_SET); - TrackCount = 1; - DeltaTicks = (size_t)ticks; - opl.AdlBank = ~0u; // Ignore AdlBank number, use dynamic banks instead + m_synth.m_embeddedBank = OPL3::CustomBankTag; // Ignore AdlBank number, use dynamic banks instead //std::printf("CMF deltas %u ticks %u, basictempo = %u\n", deltas, ticks, basictempo); - opl.AdlPercussionMode = true; - opl.m_musicMode = OPL3::MODE_CMF; - opl.m_volumeScale = OPL3::VOLUME_NATIVE; + m_synth.m_rhythmMode = true; + m_synth.m_musicMode = OPL3::MODE_CMF; + m_synth.m_volumeScale = OPL3::VOLUME_NATIVE; + + m_synth.m_numChips = 1; + m_synth.m_numFourOps = 0; + } + else if(format == MidiSequencer::Format_RSXX) + { + //opl.CartoonersVolumes = true; + m_synth.m_musicMode = OPL3::MODE_RSXX; + m_synth.m_volumeScale = OPL3::VOLUME_NATIVE; + + m_synth.m_numChips = 1; + m_synth.m_numFourOps = 0; + } + else if(format == MidiSequencer::Format_IMF) + { + //std::fprintf(stderr, "Done reading IMF file\n"); + m_synth.m_numFourOps = 0; //Don't use 4-operator channels for IMF playing! + m_synth.m_musicMode = OPL3::MODE_IMF; + + m_synth.m_numChips = 1; + m_synth.m_numFourOps = 0; } else { - // Try to identify RSXX format - if(HeaderBuf[0] == 0x7D) - { - fr.seek(0x6D, SEEK_SET); - fr.read(HeaderBuf, 6, 1); - if(std::memcmp(HeaderBuf, "rsxx}u", 6) == 0) - { - is_RSXX = true; - fr.seek(0x7D, SEEK_SET); - TrackCount = 1; - DeltaTicks = 60; - //opl.CartoonersVolumes = true; - opl.m_musicMode = OPL3::MODE_RSXX; - opl.m_volumeScale = OPL3::VOLUME_NATIVE; - } - } - - // Try parsing as an IMF file - if(!is_RSXX) - { - do - { - uint8_t raw[4]; - size_t end = static_cast(HeaderBuf[0]) + 256 * static_cast(HeaderBuf[1]); - - if(!end || (end & 3)) - break; - - size_t backup_pos = fr.tell(); - int64_t sum1 = 0, sum2 = 0; - fr.seek(2, SEEK_SET); - - for(unsigned n = 0; n < 42; ++n) - { - if(fr.read(raw, 1, 4) != 4) - break; - int64_t value1 = raw[0]; - value1 += raw[1] << 8; - sum1 += value1; - int64_t value2 = raw[2]; - value2 += raw[3] << 8; - sum2 += value2; - } - - fr.seek(static_cast(backup_pos), SEEK_SET); - - if(sum1 > sum2) - { - is_IMF = true; - DeltaTicks = 1; - } - } while(false); - } - - if(!is_IMF && !is_RSXX) - { - if(std::memcmp(HeaderBuf, "MThd\0\0\0\6", 8) != 0) - { - fr.close(); - errorStringOut = fr._fileName + ": Invalid format, Header signature is unknown!\n"; - return false; - } - - /*size_t Fmt = ReadBEint(HeaderBuf + 8, 2);*/ - TrackCount = (size_t)ReadBEint(HeaderBuf + 10, 2); - DeltaTicks = (size_t)ReadBEint(HeaderBuf + 12, 2); - } + m_synth.m_numChips = m_setup.numChips; + if(m_setup.numFourOps < 0) + adlCalculateFourOpChannels(this, true); } - TrackData.clear(); - TrackData.resize(TrackCount, std::vector()); - InvDeltaTicks = fraction(1, 1000000l * static_cast(DeltaTicks)); - if(is_CMF || is_RSXX) - Tempo = fraction(1, static_cast(DeltaTicks)); - else - Tempo = fraction(1, static_cast(DeltaTicks) * 2); - static const unsigned char EndTag[4] = {0xFF, 0x2F, 0x00, 0x00}; - size_t totalGotten = 0; - - for(size_t tk = 0; tk < TrackCount; ++tk) - { - // Read track header - size_t TrackLength; - - if(is_IMF) - { - //std::fprintf(stderr, "Reading IMF file...\n"); - size_t end = static_cast(HeaderBuf[0]) + 256 * static_cast(HeaderBuf[1]); - unsigned IMF_tempo = 1428; - static const unsigned char imf_tempo[] = {0x0,//Zero delay! - MidiEvent::T_SPECIAL, MidiEvent::ST_TEMPOCHANGE, 0x4, - static_cast(IMF_tempo >> 24), - static_cast(IMF_tempo >> 16), - static_cast(IMF_tempo >> 8), - static_cast(IMF_tempo) - }; - TrackData[tk].insert(TrackData[tk].end(), imf_tempo, imf_tempo + sizeof(imf_tempo)); - TrackData[tk].push_back(0x00); - fr.seek(2, SEEK_SET); - - while(fr.tell() < end && !fr.eof()) - { - uint8_t special_event_buf[5]; - uint8_t raw[4]; - special_event_buf[0] = MidiEvent::T_SPECIAL; - special_event_buf[1] = MidiEvent::ST_RAWOPL; - special_event_buf[2] = 0x02; - if(fr.read(raw, 1, 4) != 4) - break; - special_event_buf[3] = raw[0]; // port index - special_event_buf[4] = raw[1]; // port value - uint32_t delay = static_cast(raw[2]); - delay += 256 * static_cast(raw[3]); - totalGotten += 4; - //if(special_event_buf[3] <= 8) continue; - //fprintf(stderr, "Put %02X <- %02X, plus %04X delay\n", special_event_buf[3],special_event_buf[4], delay); - TrackData[tk].insert(TrackData[tk].end(), special_event_buf, special_event_buf + 5); - //if(delay>>21) TrackData[tk].push_back( 0x80 | ((delay>>21) & 0x7F ) ); - if(delay >> 14) - TrackData[tk].push_back(0x80 | ((delay >> 14) & 0x7F)); - if(delay >> 7) - TrackData[tk].push_back(0x80 | ((delay >> 7) & 0x7F)); - TrackData[tk].push_back(((delay >> 0) & 0x7F)); - } - - TrackData[tk].insert(TrackData[tk].end(), EndTag + 0, EndTag + 4); - //CurrentPosition.track[tk].delay = 0; - //CurrentPosition.began = true; - //std::fprintf(stderr, "Done reading IMF file\n"); - opl.NumFourOps = 0; //Don't use 4-operator channels for IMF playing! - opl.m_musicMode = OPL3::MODE_IMF; - } - else - { - // Take the rest of the file - if(is_GMF || is_CMF || is_RSXX) - { - size_t pos = fr.tell(); - fr.seek(0, SEEK_END); - TrackLength = fr.tell() - pos; - fr.seek(static_cast(pos), SEEK_SET); - } - //else if(is_MUS) // Read TrackLength from file position 4 - //{ - // size_t pos = fr.tell(); - // fr.seek(4, SEEK_SET); - // TrackLength = static_cast(fr.getc()); - // TrackLength += static_cast(fr.getc() << 8); - // fr.seek(static_cast(pos), SEEK_SET); - //} - else - { - fsize = fr.read(HeaderBuf, 1, 8); - if(std::memcmp(HeaderBuf, "MTrk", 4) != 0) - { - fr.close(); - errorStringOut = fr._fileName + ": Invalid format, MTrk signature is not found!\n"; - return false; - } - TrackLength = (size_t)ReadBEint(HeaderBuf + 4, 4); - } - - // Read track data - TrackData[tk].resize(TrackLength); - fsize = fr.read(&TrackData[tk][0], 1, TrackLength); - totalGotten += fsize; - - if(is_GMF/*|| is_MUS*/) // Note: CMF does include the track end tag. - TrackData[tk].insert(TrackData[tk].end(), EndTag + 0, EndTag + 4); - if(is_RSXX)//Finalize raw track data with a zero - TrackData[tk].push_back(0); - - //bool ok = false; - //// Read next event time - //uint64_t tkDelay = ReadVarLenEx(tk, ok); - //if(ok) - // CurrentPosition.track[tk].delay = tkDelay; - //else - //{ - // std::stringstream msg; - // msg << fr._fileName << ": invalid variable length in the track " << tk << "! (error code " << tkDelay << ")"; - // ADLMIDI_ErrorString = msg.str(); - // return false; - //} - } - } - - for(size_t tk = 0; tk < TrackCount; ++tk) - totalGotten += TrackData[tk].size(); - - if(totalGotten == 0) - { - errorStringOut = fr._fileName + ": Empty track data"; - return false; - } - - //Build new MIDI events table - if(!buildTrackData()) - { - errorStringOut = fr._fileName + ": MIDI data parsing error has occouped!\n" + errorString; - return false; - } - - opl.Reset(m_setup.emulator, m_setup.PCM_RATE, this); // Reset OPL3 chip + m_setup.tick_skip_samples_delay = 0; + m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); // Reset OPL3 chip //opl.Reset(); // ...twice (just in case someone misprogrammed OPL3 previously) - ch.clear(); - ch.resize(opl.NumChannels); + m_chipChannels.clear(); + m_chipChannels.resize(m_synth.m_numChannels); + return true; } -#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER + +bool MIDIplay::LoadMIDI(const std::string &filename) +{ + FileAndMemReader file; + file.openFile(filename.c_str()); + if(!LoadMIDI_pre()) + return false; + if(!m_sequencer.loadMIDI(file)) + { + errorStringOut = m_sequencer.getErrorString(); + return false; + } + if(!LoadMIDI_post()) + return false; + return true; +} + +bool MIDIplay::LoadMIDI(const void *data, size_t size) +{ + FileAndMemReader file; + file.openData(data, size); + if(!LoadMIDI_pre()) + return false; + if(!m_sequencer.loadMIDI(file)) + { + errorStringOut = m_sequencer.getErrorString(); + return false; + } + if(!LoadMIDI_post()) + return false; + return true; +} + +#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ diff --git a/src/sound/adlmidi/adlmidi_midiplay.cpp b/src/sound/adlmidi/adlmidi_midiplay.cpp index 8996d67d0..1e1da0789 100644 --- a/src/sound/adlmidi/adlmidi_midiplay.cpp +++ b/src/sound/adlmidi/adlmidi_midiplay.cpp @@ -25,7 +25,7 @@ // Mapping from MIDI volume level to OPL level value. -static const uint8_t DMX_volume_mapping_table[128] = +static const uint_fast32_t DMX_volume_mapping_table[128] = { 0, 1, 3, 5, 6, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, @@ -45,7 +45,7 @@ static const uint8_t DMX_volume_mapping_table[128] = 124, 124, 125, 125, 126, 126, 127, 127, }; -static const uint8_t W9X_volume_mapping_table[32] = +static const uint_fast32_t W9X_volume_mapping_table[32] = { 63, 63, 40, 36, 32, 28, 23, 21, 19, 17, 15, 14, 13, 12, 11, 10, @@ -93,877 +93,179 @@ static const uint8_t PercussionMap[256] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; +enum { MasterVolumeDefault = 127 }; + inline bool isXgPercChannel(uint8_t msb, uint8_t lsb) { return (msb == 0x7E || msb == 0x7F) && (lsb == 0); } -void MIDIplay::AdlChannel::AddAge(int64_t ms) +void MIDIplay::AdlChannel::addAge(int64_t us) { - const int64_t neg = static_cast(-0x1FFFFFFFl); + const int64_t neg = 1000 * static_cast(-0x1FFFFFFFll); if(users_empty()) - koff_time_until_neglible = std::max(int64_t(koff_time_until_neglible - ms), neg); + { + koff_time_until_neglible_us = std::max(koff_time_until_neglible_us - us, neg); + if(koff_time_until_neglible_us < 0) + koff_time_until_neglible_us = 0; + } else { - koff_time_until_neglible = 0; + koff_time_until_neglible_us = 0; for(LocationData *i = users_first; i; i = i->next) { if(!i->fixed_sustain) - i->kon_time_until_neglible = std::max(i->kon_time_until_neglible - ms, neg); - i->vibdelay += ms; + i->kon_time_until_neglible_us = std::max(i->kon_time_until_neglible_us - us, neg); + i->vibdelay_us += us; } } } -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - -MIDIplay::MidiEvent::MidiEvent() : - type(T_UNKNOWN), - subtype(T_UNKNOWN), - channel(0), - isValid(1), - absPosition(0) -{} - - -MIDIplay::MidiTrackRow::MidiTrackRow() : - time(0.0), - delay(0), - absPos(0), - timeDelay(0.0) -{} - -void MIDIplay::MidiTrackRow::reset() -{ - time = 0.0; - delay = 0; - absPos = 0; - timeDelay = 0.0; - events.clear(); -} - -void MIDIplay::MidiTrackRow::sortEvents(bool *noteStates) -{ - typedef std::vector EvtArr; - EvtArr metas; - EvtArr noteOffs; - EvtArr controllers; - EvtArr anyOther; - - metas.reserve(events.size()); - noteOffs.reserve(events.size()); - controllers.reserve(events.size()); - anyOther.reserve(events.size()); - - for(size_t i = 0; i < events.size(); i++) - { - if(events[i].type == MidiEvent::T_NOTEOFF) - noteOffs.push_back(events[i]); - else if((events[i].type == MidiEvent::T_CTRLCHANGE) - || (events[i].type == MidiEvent::T_PATCHCHANGE) - || (events[i].type == MidiEvent::T_WHEEL) - || (events[i].type == MidiEvent::T_CHANAFTTOUCH)) - { - controllers.push_back(events[i]); - } - else if((events[i].type == MidiEvent::T_SPECIAL) && (events[i].subtype == MidiEvent::ST_MARKER)) - metas.push_back(events[i]); - else - anyOther.push_back(events[i]); - } - - /* - * If Note-Off and it's Note-On is on the same row - move this damned note off down! - */ - if(noteStates) - { - std::set markAsOn; - for(size_t i = 0; i < anyOther.size(); i++) - { - const MidiEvent e = anyOther[i]; - if(e.type == MidiEvent::T_NOTEON) - { - const size_t note_i = (e.channel * 255) + (e.data[0] & 0x7F); - //Check, was previously note is on or off - bool wasOn = noteStates[note_i]; - markAsOn.insert(note_i); - // Detect zero-length notes are following previously pressed note - int noteOffsOnSameNote = 0; - for(EvtArr::iterator j = noteOffs.begin(); j != noteOffs.end();) - { - //If note was off, and note-off on same row with note-on - move it down! - if( - ((*j).channel == e.channel) && - ((*j).data[0] == e.data[0]) - ) - { - //If note is already off OR more than one note-off on same row and same note - if(!wasOn || (noteOffsOnSameNote != 0)) - { - anyOther.push_back(*j); - j = noteOffs.erase(j); - markAsOn.erase(note_i); - continue; - } - else - { - //When same row has many note-offs on same row - //that means a zero-length note follows previous note - //it must be shuted down - noteOffsOnSameNote++; - } - } - j++; - } - } - } - - //Mark other notes as released - for(EvtArr::iterator j = noteOffs.begin(); j != noteOffs.end(); j++) - { - size_t note_i = (j->channel * 255) + (j->data[0] & 0x7F); - noteStates[note_i] = false; - } - - for(std::set::iterator j = markAsOn.begin(); j != markAsOn.end(); j++) - noteStates[*j] = true; - } - /***********************************************************************************/ - - events.clear(); - events.insert(events.end(), noteOffs.begin(), noteOffs.end()); - events.insert(events.end(), metas.begin(), metas.end()); - events.insert(events.end(), controllers.begin(), controllers.end()); - events.insert(events.end(), anyOther.begin(), anyOther.end()); -} -#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -bool MIDIplay::buildTrackData() -{ - fullSongTimeLength = 0.0; - loopStartTime = -1.0; - loopEndTime = -1.0; - musTitle.clear(); - musCopyright.clear(); - musTrackTitles.clear(); - musMarkers.clear(); - caugh_missing_instruments.clear(); - caugh_missing_banks_melodic.clear(); - caugh_missing_banks_percussion.clear(); - trackDataNew.clear(); - const size_t trackCount = TrackData.size(); - trackDataNew.resize(trackCount, MidiTrackQueue()); - - invalidLoop = false; - bool gotLoopStart = false, gotLoopEnd = false, gotLoopEventInThisRow = false; - //! Tick position of loop start tag - uint64_t loopStartTicks = 0; - //! Tick position of loop end tag - uint64_t loopEndTicks = 0; - //! Full length of song in ticks - uint64_t ticksSongLength = 0; - //! Cache for error message strign - char error[150]; - - CurrentPositionNew.track.clear(); - CurrentPositionNew.track.resize(trackCount); - - //! Caches note on/off states. - bool noteStates[16 * 255]; - /* This is required to carefully detect zero-length notes * - * and avoid a move of "note-off" event over "note-on" while sort. * - * Otherwise, after sort those notes will play infinite sound */ - - //Tempo change events - std::vector tempos; - - /* - * TODO: Make this be safer for memory in case of broken input data - * which may cause going away of available track data (and then give a crash!) - * - * POST: Check this more carefully for possible vulnuabilities are can crash this - */ - for(size_t tk = 0; tk < trackCount; ++tk) - { - uint64_t abs_position = 0; - int status = 0; - MidiEvent event; - bool ok = false; - uint8_t *end = TrackData[tk].data() + TrackData[tk].size(); - uint8_t *trackPtr = TrackData[tk].data(); - std::memset(noteStates, 0, sizeof(noteStates)); - - //Time delay that follows the first event in the track - { - MidiTrackRow evtPos; - if(opl.m_musicMode == OPL3::MODE_RSXX) - ok = true; - else - evtPos.delay = ReadVarLenEx(&trackPtr, end, ok); - if(!ok) - { - int len = snprintf(error, 150, "buildTrackData: Can't read variable-length value at begin of track %d.\n", (int)tk); - if((len > 0) && (len < 150)) - errorString += std::string(error, (size_t)len); - return false; - } - - //HACK: Begin every track with "Reset all controllers" event to avoid controllers state break came from end of song - for(uint8_t chan = 0; chan < 16; chan++) - { - MidiEvent event; - event.type = MidiEvent::T_CTRLCHANGE; - event.channel = chan; - event.data.push_back(121); - event.data.push_back(0); - evtPos.events.push_back(event); - } - - evtPos.absPos = abs_position; - abs_position += evtPos.delay; - trackDataNew[tk].push_back(evtPos); - } - - MidiTrackRow evtPos; - do - { - event = parseEvent(&trackPtr, end, status); - if(!event.isValid) - { - int len = snprintf(error, 150, "buildTrackData: Fail to parse event in the track %d.\n", (int)tk); - if((len > 0) && (len < 150)) - errorString += std::string(error, (size_t)len); - return false; - } - - evtPos.events.push_back(event); - if(event.type == MidiEvent::T_SPECIAL) - { - if(event.subtype == MidiEvent::ST_TEMPOCHANGE) - { - event.absPosition = abs_position; - tempos.push_back(event); - } - else if(!invalidLoop && (event.subtype == MidiEvent::ST_LOOPSTART)) - { - /* - * loopStart is invalid when: - * - starts together with loopEnd - * - appears more than one time in same MIDI file - */ - if(gotLoopStart || gotLoopEventInThisRow) - invalidLoop = true; - else - { - gotLoopStart = true; - loopStartTicks = abs_position; - } - //In this row we got loop event, register this! - gotLoopEventInThisRow = true; - } - else if(!invalidLoop && (event.subtype == MidiEvent::ST_LOOPEND)) - { - /* - * loopEnd is invalid when: - * - starts before loopStart - * - starts together with loopStart - * - appars more than one time in same MIDI file - */ - if(gotLoopEnd || gotLoopEventInThisRow) - invalidLoop = true; - else - { - gotLoopEnd = true; - loopEndTicks = abs_position; - } - //In this row we got loop event, register this! - gotLoopEventInThisRow = true; - } - } - - if(event.subtype != MidiEvent::ST_ENDTRACK)//Don't try to read delta after EndOfTrack event! - { - evtPos.delay = ReadVarLenEx(&trackPtr, end, ok); - if(!ok) - { - /* End of track has been reached! However, there is no EOT event presented */ - event.type = MidiEvent::T_SPECIAL; - event.subtype = MidiEvent::ST_ENDTRACK; - } - } - - if((evtPos.delay > 0) || (event.subtype == MidiEvent::ST_ENDTRACK)) - { - evtPos.absPos = abs_position; - abs_position += evtPos.delay; - evtPos.sortEvents(noteStates); - trackDataNew[tk].push_back(evtPos); - evtPos.reset(); - gotLoopEventInThisRow = false; - } - } - while((trackPtr <= end) && (event.subtype != MidiEvent::ST_ENDTRACK)); - - if(ticksSongLength < abs_position) - ticksSongLength = abs_position; - //Set the chain of events begin - if(trackDataNew[tk].size() > 0) - CurrentPositionNew.track[tk].pos = trackDataNew[tk].begin(); - } - - if(gotLoopStart && !gotLoopEnd) - { - gotLoopEnd = true; - loopEndTicks = ticksSongLength; - } - - //loopStart must be located before loopEnd! - if(loopStartTicks >= loopEndTicks) - invalidLoop = true; - - /********************************************************************************/ - //Calculate time basing on collected tempo events - /********************************************************************************/ - for(size_t tk = 0; tk < trackCount; ++tk) - { - fraction currentTempo = Tempo; - double time = 0.0; - uint64_t abs_position = 0; - size_t tempo_change_index = 0; - MidiTrackQueue &track = trackDataNew[tk]; - if(track.empty()) - continue;//Empty track is useless! - -#ifdef DEBUG_TIME_CALCULATION - std::fprintf(stdout, "\n============Track %" PRIuPTR "=============\n", tk); - std::fflush(stdout); -#endif - - MidiTrackRow *posPrev = &(*(track.begin()));//First element - for(MidiTrackQueue::iterator it = track.begin(); it != track.end(); it++) - { -#ifdef DEBUG_TIME_CALCULATION - bool tempoChanged = false; -#endif - MidiTrackRow &pos = *it; - if((posPrev != &pos) && //Skip first event - (!tempos.empty()) && //Only when in-track tempo events are available - (tempo_change_index < tempos.size()) - ) - { - // If tempo event is going between of current and previous event - if(tempos[tempo_change_index].absPosition <= pos.absPos) - { - //Stop points: begin point and tempo change points are before end point - std::vector points; - fraction t; - TempoChangePoint firstPoint = {posPrev->absPos, currentTempo}; - points.push_back(firstPoint); - - //Collect tempo change points between previous and current events - do - { - TempoChangePoint tempoMarker; - MidiEvent &tempoPoint = tempos[tempo_change_index]; - tempoMarker.absPos = tempoPoint.absPosition; - tempoMarker.tempo = InvDeltaTicks * fraction(ReadBEint(tempoPoint.data.data(), tempoPoint.data.size())); - points.push_back(tempoMarker); - tempo_change_index++; - } - while((tempo_change_index < tempos.size()) && - (tempos[tempo_change_index].absPosition <= pos.absPos)); - - // Re-calculate time delay of previous event - time -= posPrev->timeDelay; - posPrev->timeDelay = 0.0; - - for(size_t i = 0, j = 1; j < points.size(); i++, j++) - { - /* If one or more tempo events are appears between of two events, - * calculate delays between each tempo point, begin and end */ - uint64_t midDelay = 0; - //Delay between points - midDelay = points[j].absPos - points[i].absPos; - //Time delay between points - t = midDelay * currentTempo; - posPrev->timeDelay += t.value(); - - //Apply next tempo - currentTempo = points[j].tempo; -#ifdef DEBUG_TIME_CALCULATION - tempoChanged = true; -#endif - } - //Then calculate time between last tempo change point and end point - TempoChangePoint tailTempo = points.back(); - uint64_t postDelay = pos.absPos - tailTempo.absPos; - t = postDelay * currentTempo; - posPrev->timeDelay += t.value(); - - //Store Common time delay - posPrev->time = time; - time += posPrev->timeDelay; - } - } - - fraction t = pos.delay * currentTempo; - pos.timeDelay = t.value(); - pos.time = time; - time += pos.timeDelay; - - //Capture markers after time value calculation - for(size_t i = 0; i < pos.events.size(); i++) - { - MidiEvent &e = pos.events[i]; - if((e.type == MidiEvent::T_SPECIAL) && (e.subtype == MidiEvent::ST_MARKER)) - { - MIDI_MarkerEntry marker; - marker.label = std::string((char *)e.data.data(), e.data.size()); - marker.pos_ticks = pos.absPos; - marker.pos_time = pos.time; - musMarkers.push_back(marker); - } - } - - //Capture loop points time positions - if(!invalidLoop) - { - // Set loop points times - if(loopStartTicks == pos.absPos) - loopStartTime = pos.time; - else if(loopEndTicks == pos.absPos) - loopEndTime = pos.time; - } - -#ifdef DEBUG_TIME_CALCULATION - std::fprintf(stdout, "= %10" PRId64 " = %10f%s\n", pos.absPos, pos.time, tempoChanged ? " <----TEMPO CHANGED" : ""); - std::fflush(stdout); -#endif - - abs_position += pos.delay; - posPrev = &pos; - } - - if(time > fullSongTimeLength) - fullSongTimeLength = time; - } - - fullSongTimeLength += postSongWaitDelay; - //Set begin of the music - trackBeginPositionNew = CurrentPositionNew; - //Initial loop position will begin at begin of track until passing of the loop point - LoopBeginPositionNew = CurrentPositionNew; - - /********************************************************************************/ - //Resolve "hell of all times" of too short drum notes: - //move too short percussion note-offs far far away as possible - /********************************************************************************/ -#if 1 //Use this to record WAVEs for comparison before/after implementing of this - if(opl.m_musicMode == OPL3::MODE_MIDI)//Percussion fix is needed for MIDI only, not for IMF/RSXX or CMF - { - //! Minimal real time in seconds -#define DRUM_NOTE_MIN_TIME 0.03 - //! Minimal ticks count -#define DRUM_NOTE_MIN_TICKS 15 - struct NoteState - { - double delay; - uint64_t delayTicks; - bool isOn; - char ___pad[7]; - } drNotes[255]; - uint16_t banks[16]; - - for(size_t tk = 0; tk < trackCount; ++tk) - { - std::memset(drNotes, 0, sizeof(drNotes)); - std::memset(banks, 0, sizeof(banks)); - MidiTrackQueue &track = trackDataNew[tk]; - if(track.empty()) - continue;//Empty track is useless! - - for(MidiTrackQueue::iterator it = track.begin(); it != track.end(); it++) - { - MidiTrackRow &pos = *it; - - for(ssize_t e = 0; e < (ssize_t)pos.events.size(); e++) - { - MidiEvent *et = &pos.events[(size_t)e]; - - /* Set MSB/LSB bank */ - if(et->type == MidiEvent::T_CTRLCHANGE) - { - uint8_t ctrlno = et->data[0]; - uint8_t value = et->data[1]; - switch(ctrlno) - { - case 0: // Set bank msb (GM bank) - banks[et->channel] = uint16_t(uint16_t(value) << 8) | uint16_t(banks[et->channel] & 0x00FF); - break; - case 32: // Set bank lsb (XG bank) - banks[et->channel] = (banks[et->channel] & 0xFF00) | (uint16_t(value) & 0x00FF); - break; - } - continue; - } - - bool percussion = (et->channel == 9) || - banks[et->channel] == 0x7E00 || //XG SFX1/SFX2 channel (16128 signed decimal) - banks[et->channel] == 0x7F00; //XG Percussion channel (16256 signed decimal) - if(!percussion) - continue; - - if(et->type == MidiEvent::T_NOTEON) - { - uint8_t note = et->data[0] & 0x7F; - NoteState &ns = drNotes[note]; - ns.isOn = true; - ns.delay = 0.0; - ns.delayTicks = 0; - } - else if(et->type == MidiEvent::T_NOTEOFF) - { - uint8_t note = et->data[0] & 0x7F; - NoteState &ns = drNotes[note]; - if(ns.isOn) - { - ns.isOn = false; - if(ns.delayTicks < DRUM_NOTE_MIN_TICKS || ns.delay < DRUM_NOTE_MIN_TIME)//If note is too short - { - //Move it into next event position if that possible - for(MidiTrackQueue::iterator itNext = it; - itNext != track.end(); - itNext++) - { - MidiTrackRow &posN = *itNext; - if(ns.delayTicks > DRUM_NOTE_MIN_TICKS && ns.delay > DRUM_NOTE_MIN_TIME) - { - //Put note-off into begin of next event list - posN.events.insert(posN.events.begin(), pos.events[(size_t)e]); - //Renive this event from a current row - pos.events.erase(pos.events.begin() + (int)e); - e--; - break; - } - ns.delay += posN.timeDelay; - ns.delayTicks += posN.delay; - } - } - ns.delay = 0.0; - ns.delayTicks = 0; - } - } - } - - //Append time delays to sustaining notes - for(size_t no = 0; no < 128; no++) - { - NoteState &ns = drNotes[no]; - if(ns.isOn) - { - ns.delay += pos.timeDelay; - ns.delayTicks += pos.delay; - } - } - } - } -#undef DRUM_NOTE_MIN_TIME -#undef DRUM_NOTE_MIN_TICKS - } -#endif - - return true; -} -#endif - - MIDIplay::MIDIplay(unsigned long sampleRate): - cmf_percussion_mode(false), - m_arpeggioCounter(0), - m_audioTickCounter(0) -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - , fullSongTimeLength(0.0), - postSongWaitDelay(1.0), - loopStartTime(-1.0), - loopEndTime(-1.0), - tempoMultiplier(1.0), - atEnd(false), - loopStart(false), - loopEnd(false), - invalidLoop(false) + m_cmfPercussionMode(false), + m_masterVolume(MasterVolumeDefault), + m_sysExDeviceId(0), + m_synthMode(Mode_XG), + m_arpeggioCounter(0) +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) + , m_audioTickCounter(0) #endif { - devices.clear(); + m_midiDevices.clear(); - m_setup.emulator = ADLMIDI_EMU_NUKED; + m_setup.emulator = adl_getLowestEmulator(); m_setup.runAtPcmRate = false; m_setup.PCM_RATE = sampleRate; m_setup.mindelay = 1.0 / (double)m_setup.PCM_RATE; m_setup.maxdelay = 512.0 / (double)m_setup.PCM_RATE; - m_setup.AdlBank = 0; - m_setup.NumFourOps = 7; - m_setup.NumCards = 2; - m_setup.HighTremoloMode = -1; - m_setup.HighVibratoMode = -1; - m_setup.AdlPercussionMode = -1; - m_setup.LogarithmicVolumes = false; - m_setup.VolumeModel = ADLMIDI_VolumeModel_AUTO; + m_setup.bankId = 0; + m_setup.numFourOps = -1; + m_setup.numChips = 2; + m_setup.deepTremoloMode = -1; + m_setup.deepVibratoMode = -1; + m_setup.rhythmMode = -1; + m_setup.logarithmicVolumes = false; + m_setup.volumeScaleModel = ADLMIDI_VolumeModel_AUTO; //m_setup.SkipForward = 0; - m_setup.loopingIsEnabled = false; - m_setup.ScaleModulators = -1; + m_setup.scaleModulators = -1; m_setup.fullRangeBrightnessCC74 = false; m_setup.delay = 0.0; m_setup.carry = 0.0; m_setup.tick_skip_samples_delay = 0; +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + initSequencerInterface(); +#endif + resetMIDI(); applySetup(); - ChooseDevice("none"); realTime_ResetState(); } void MIDIplay::applySetup() { + m_synth.m_musicMode = OPL3::MODE_MIDI; + m_setup.tick_skip_samples_delay = 0; - opl.runAtPcmRate = m_setup.runAtPcmRate; + m_synth.m_runAtPcmRate = m_setup.runAtPcmRate; - if(opl.AdlBank != ~0u) - opl.dynamic_bank_setup = adlbanksetup[m_setup.AdlBank]; +#ifndef DISABLE_EMBEDDED_BANKS + if(m_synth.m_embeddedBank != OPL3::CustomBankTag) + m_synth.m_insBankSetup = adlbanksetup[m_setup.bankId]; +#endif - opl.HighTremoloMode = m_setup.HighTremoloMode < 0 ? - opl.dynamic_bank_setup.deepTremolo : - (m_setup.HighTremoloMode != 0); - opl.HighVibratoMode = m_setup.HighVibratoMode < 0 ? - opl.dynamic_bank_setup.deepVibrato : - (m_setup.HighVibratoMode != 0); - opl.AdlPercussionMode = m_setup.AdlPercussionMode < 0 ? - opl.dynamic_bank_setup.adLibPercussions : - (m_setup.AdlPercussionMode != 0); - opl.ScaleModulators = m_setup.ScaleModulators < 0 ? - opl.dynamic_bank_setup.scaleModulators : - (m_setup.ScaleModulators != 0); - if(m_setup.LogarithmicVolumes) - opl.ChangeVolumeRangesModel(ADLMIDI_VolumeModel_NativeOPL3); - opl.m_musicMode = OPL3::MODE_MIDI; - opl.ChangeVolumeRangesModel(static_cast(m_setup.VolumeModel)); - if(m_setup.VolumeModel == ADLMIDI_VolumeModel_AUTO)//Use bank default volume model - opl.m_volumeScale = (OPL3::VolumesScale)opl.dynamic_bank_setup.volumeModel; + m_synth.m_deepTremoloMode = m_setup.deepTremoloMode < 0 ? + m_synth.m_insBankSetup.deepTremolo : + (m_setup.deepTremoloMode != 0); + m_synth.m_deepVibratoMode = m_setup.deepVibratoMode < 0 ? + m_synth.m_insBankSetup.deepVibrato : + (m_setup.deepVibratoMode != 0); + m_synth.m_rhythmMode = m_setup.rhythmMode < 0 ? + m_synth.m_insBankSetup.adLibPercussions : + (m_setup.rhythmMode != 0); + m_synth.m_scaleModulators = m_setup.scaleModulators < 0 ? + m_synth.m_insBankSetup.scaleModulators : + (m_setup.scaleModulators != 0); - opl.NumCards = m_setup.NumCards; - opl.NumFourOps = m_setup.NumFourOps; - cmf_percussion_mode = false; + if(m_setup.logarithmicVolumes) + m_synth.setVolumeScaleModel(ADLMIDI_VolumeModel_NativeOPL3); + else + m_synth.setVolumeScaleModel(static_cast(m_setup.volumeScaleModel)); - opl.Reset(m_setup.emulator, m_setup.PCM_RATE, this); - ch.clear(); - ch.resize(opl.NumChannels); + if(m_setup.volumeScaleModel == ADLMIDI_VolumeModel_AUTO)//Use bank default volume model + m_synth.m_volumeScale = (OPL3::VolumesScale)m_synth.m_insBankSetup.volumeModel; + + m_synth.m_numChips = m_setup.numChips; + m_cmfPercussionMode = false; + + if(m_setup.numFourOps >= 0) + m_synth.m_numFourOps = m_setup.numFourOps; + else + adlCalculateFourOpChannels(this, true); + + m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); + m_chipChannels.clear(); + m_chipChannels.resize(m_synth.m_numChannels); // Reset the arpeggio counter m_arpeggioCounter = 0; } -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -uint64_t MIDIplay::ReadVarLen(uint8_t **ptr) +void MIDIplay::partialReset() { - uint64_t result = 0; - for(;;) - { - uint8_t byte = *((*ptr)++); - result = (result << 7) + (byte & 0x7F); - if(!(byte & 0x80)) - break; - } - return result; + realTime_panic(); + m_setup.tick_skip_samples_delay = 0; + m_synth.m_runAtPcmRate = m_setup.runAtPcmRate; + m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); + m_chipChannels.clear(); + m_chipChannels.resize((size_t)m_synth.m_numChannels); } -uint64_t MIDIplay::ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok) +void MIDIplay::resetMIDI() { - uint64_t result = 0; - ok = false; + m_masterVolume = MasterVolumeDefault; + m_sysExDeviceId = 0; + m_synthMode = Mode_XG; + m_arpeggioCounter = 0; - for(;;) - { - if(*ptr >= end) - return 2; - unsigned char byte = *((*ptr)++); - result = (result << 7) + (byte & 0x7F); - if(!(byte & 0x80)) - break; - } + m_midiChannels.clear(); + m_midiChannels.resize(16, MIDIchannel()); - ok = true; - return result; + caugh_missing_instruments.clear(); + caugh_missing_banks_melodic.clear(); + caugh_missing_banks_percussion.clear(); } -double MIDIplay::Tick(double s, double granularity) +void MIDIplay::TickIterators(double s) { - s *= tempoMultiplier; -#ifdef ENABLE_BEGIN_SILENCE_SKIPPING - if(CurrentPositionNew.began) + for(uint16_t c = 0; c < m_synth.m_numChannels; ++c) + m_chipChannels[c].addAge(static_cast(s * 1e6)); + updateVibrato(s); + updateArpeggio(s); +#if !defined(ADLMIDI_AUDIO_TICK_HANDLER) + updateGlide(s); #endif - CurrentPositionNew.wait -= s; - CurrentPositionNew.absTimePosition += s; - - int antiFreezeCounter = 10000;//Limit 10000 loops to avoid freezing - while((CurrentPositionNew.wait <= granularity * 0.5) && (antiFreezeCounter > 0)) - { - //std::fprintf(stderr, "wait = %g...\n", CurrentPosition.wait); - if(!ProcessEventsNew()) - break; - if(CurrentPositionNew.wait <= 0.0) - antiFreezeCounter--; - } - - if(antiFreezeCounter <= 0) - CurrentPositionNew.wait += 1.0;/* Add extra 1 second when over 10000 events - with zero delay are been detected */ - - for(uint16_t c = 0; c < opl.NumChannels; ++c) - ch[c].AddAge(static_cast(s * 1000.0)); - - UpdateVibrato(s); - UpdateArpeggio(s); - - if(CurrentPositionNew.wait < 0.0)//Avoid negative delay value! - return 0.0; - - return CurrentPositionNew.wait; } -#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ - -void MIDIplay::TickIteratos(double s) -{ - for(uint16_t c = 0; c < opl.NumChannels; ++c) - ch[c].AddAge(static_cast(s * 1000.0)); - UpdateVibrato(s); - UpdateArpeggio(s); -} - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - -void MIDIplay::seek(double seconds) -{ - if(seconds < 0.0) - return;//Seeking negative position is forbidden! :-P - const double granularity = m_setup.mindelay, - granualityHalf = granularity * 0.5, - s = seconds;//m_setup.delay < m_setup.maxdelay ? m_setup.delay : m_setup.maxdelay; - - /* Attempt to go away out of song end must rewind position to begin */ - if(seconds > fullSongTimeLength) - { - rewind(); - return; - } - - bool loopFlagState = m_setup.loopingIsEnabled; - // Turn loop pooints off because it causes wrong position rememberin on a quick seek - m_setup.loopingIsEnabled = false; - - /* - * Seeking search is similar to regular ticking, except of next things: - * - We don't processsing arpeggio and vibrato - * - To keep correctness of the state after seek, begin every search from begin - * - All sustaining notes must be killed - * - Ignore Note-On events - */ - rewind(); - - /* - * Set "loop Start" to false to prevent overwrite of loopStart position with - * seek destinition position - * - * TODO: Detect & set loopStart position on load time to don't break loop while seeking - */ - loopStart = false; - - while((CurrentPositionNew.absTimePosition < seconds) && - (CurrentPositionNew.absTimePosition < fullSongTimeLength)) - { - CurrentPositionNew.wait -= s; - CurrentPositionNew.absTimePosition += s; - int antiFreezeCounter = 10000;//Limit 10000 loops to avoid freezing - double dstWait = CurrentPositionNew.wait + granualityHalf; - while((CurrentPositionNew.wait <= granualityHalf)/*&& (antiFreezeCounter > 0)*/) - { - //std::fprintf(stderr, "wait = %g...\n", CurrentPosition.wait); - if(!ProcessEventsNew(true)) - break; - //Avoid freeze because of no waiting increasing in more than 10000 cycles - if(CurrentPositionNew.wait <= dstWait) - antiFreezeCounter--; - else - { - dstWait = CurrentPositionNew.wait + granualityHalf; - antiFreezeCounter = 10000; - } - } - if(antiFreezeCounter <= 0) - CurrentPositionNew.wait += 1.0;/* Add extra 1 second when over 10000 events - with zero delay are been detected */ - } - - if(CurrentPositionNew.wait < 0.0) - CurrentPositionNew.wait = 0.0; - - m_setup.loopingIsEnabled = loopFlagState; - m_setup.delay = CurrentPositionNew.wait; - m_setup.carry = 0.0; -} - -double MIDIplay::tell() -{ - return CurrentPositionNew.absTimePosition; -} - -double MIDIplay::timeLength() -{ - return fullSongTimeLength; -} - -double MIDIplay::getLoopStart() -{ - return loopStartTime; -} - -double MIDIplay::getLoopEnd() -{ - return loopEndTime; -} - -void MIDIplay::rewind() -{ - Panic(); - KillSustainingNotes(-1, -1); - CurrentPositionNew = trackBeginPositionNew; - atEnd = false; - loopStart = true; - loopEnd = false; - //invalidLoop = false;//No more needed here as this flag is set on load time -} - -void MIDIplay::setTempo(double tempo) -{ - tempoMultiplier = tempo; -} -#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ void MIDIplay::realTime_ResetState() { - for(size_t ch = 0; ch < Ch.size(); ch++) + for(size_t ch = 0; ch < m_midiChannels.size(); ch++) { - MIDIchannel &chan = Ch[ch]; + MIDIchannel &chan = m_midiChannels[ch]; chan.resetAllControllers(); - chan.volume = (opl.m_musicMode == OPL3::MODE_RSXX) ? 127 : 100; + chan.volume = (m_synth.m_musicMode == OPL3::MODE_RSXX) ? 127 : 100; chan.vibpos = 0.0; chan.lastlrpn = 0; chan.lastmrpn = 0; chan.nrpn = false; - NoteUpdate_All(uint16_t(ch), Upd_All); - NoteUpdate_All(uint16_t(ch), Upd_Off); + if((m_synthMode & Mode_GS) != 0)// Reset custom drum channels on GS + chan.is_xg_percussion = false; + noteUpdateAll(uint16_t(ch), Upd_All); + noteUpdateAll(uint16_t(ch), Upd_Off); } + m_masterVolume = MasterVolumeDefault; } bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) @@ -971,20 +273,23 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(note >= 128) note = 127; - if((opl.m_musicMode == OPL3::MODE_RSXX) && (velocity != 0)) + if((m_synth.m_musicMode == OPL3::MODE_RSXX) && (velocity != 0)) { // Check if this is just a note after-touch - MIDIchannel::activenoteiterator i = Ch[channel].activenotes_find(note); + MIDIchannel::activenoteiterator i = m_midiChannels[channel].activenotes_find(note); if(i) { + const int veloffset = i->ains->midi_velocity_offset; + velocity = (uint8_t)std::min(127, std::max(1, (int)velocity + veloffset)); i->vol = velocity; - NoteUpdate(channel, i, Upd_Volume); + noteUpdate(channel, i, Upd_Volume); return false; } } - channel = channel % 16; - NoteOff(channel, note); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + noteOff(channel, note); // On Note on, Keyoff the note first, just in case keyoff // was omitted; this fixes Dance of sugar-plum fairy // by Microsoft. Now that we've done a Keyoff, @@ -993,89 +298,108 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(velocity == 0) return false; - MIDIchannel &midiChan = Ch[channel]; + MIDIchannel &midiChan = m_midiChannels[channel]; size_t midiins = midiChan.patch; - bool isPercussion = (channel % 16 == 9); - bool isXgPercussion = false; + bool isPercussion = (channel % 16 == 9) || midiChan.is_xg_percussion; - uint16_t bank = 0; - if(midiChan.bank_msb || midiChan.bank_lsb) - { - bank = (uint16_t(midiChan.bank_msb) * 256) + uint16_t(midiChan.bank_lsb); - //0x7E00 - XG SFX1/SFX2 channel (16128 signed decimal) - //0x7F00 - XG Percussion channel (16256 signed decimal) - if(bank == 0x7E00 || bank == 0x7F00) - { - //Let XG SFX1/SFX2 bank will have LSB==1 (128...255 range in WOPN file) - //Let XG Percussion bank will use (0...127 range in WOPN file) - bank = (uint16_t)midiins + ((bank == 0x7E00) ? 128 : 0); // MIDI instrument defines the patch - midiins = note; // Percussion instrument - isXgPercussion = true; - isPercussion = false; - } - } + size_t bank = (midiChan.bank_msb * 256) + midiChan.bank_lsb; if(isPercussion) { - bank = (uint16_t)midiins; // MIDI instrument defines the patch + // == XG bank numbers == + // 0x7E00 - XG "SFX Kits" SFX1/SFX2 channel (16128 signed decimal) + // 0x7F00 - XG "Drum Kits" Percussion channel (16256 signed decimal) + + // MIDI instrument defines the patch: + if((m_synthMode & Mode_XG) != 0) + { + // Let XG SFX1/SFX2 bank will go in 128...255 range of LSB in WOPN file) + // Let XG Percussion bank will use (0...127 LSB range in WOPN file) + + // Choose: SFX or Drum Kits + bank = midiins + ((bank == 0x7E00) ? 128 : 0); + } + else + { + bank = midiins; + } midiins = note; // Percussion instrument } - if(isPercussion || isXgPercussion) + + if(isPercussion) bank += OPL3::PercussionTag; - const adlinsdata2 *ains = &OPL3::emptyInstrument; + const adlinsdata2 *ains = &OPL3::m_emptyInstrument; //Set bank bank const OPL3::Bank *bnk = NULL; - if((bank & ~(uint16_t)OPL3::PercussionTag) > 0) + bool caughtMissingBank = false; + if((bank & ~static_cast(OPL3::PercussionTag)) > 0) { - OPL3::BankMap::iterator b = opl.dynamic_banks.find(bank); - if(b != opl.dynamic_banks.end()) + OPL3::BankMap::iterator b = m_synth.m_insBanks.find(bank); + if(b != m_synth.m_insBanks.end()) bnk = &b->second; - if(bnk) ains = &bnk->ins[midiins]; - else if(hooks.onDebugMessage) + else + caughtMissingBank = true; + } + + //Or fall back to bank ignoring LSB (GS) + if((ains->flags & adlinsdata::Flag_NoSound) && ((m_synthMode & Mode_GS) != 0)) + { + size_t fallback = bank & ~(size_t)0x7F; + if(fallback != bank) { - std::set &missing = (isPercussion || isXgPercussion) ? - caugh_missing_banks_percussion : caugh_missing_banks_melodic; - const char *text = (isPercussion || isXgPercussion) ? - "percussion" : "melodic"; - if(missing.insert(bank).second) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing %s MIDI bank %i (patch %i)", channel, text, bank, midiins); + OPL3::BankMap::iterator b = m_synth.m_insBanks.find(fallback); + caughtMissingBank = false; + if(b != m_synth.m_insBanks.end()) + bnk = &b->second; + if(bnk) + ains = &bnk->ins[midiins]; + else + caughtMissingBank = true; } } - //Or fall back to first bank - if(ains->flags & adlinsdata::Flag_NoSound) - { - OPL3::BankMap::iterator b = opl.dynamic_banks.find(bank & OPL3::PercussionTag); - if(b != opl.dynamic_banks.end()) - bnk = &b->second; + if(caughtMissingBank && hooks.onDebugMessage) + { + std::set &missing = (isPercussion) ? + caugh_missing_banks_percussion : caugh_missing_banks_melodic; + const char *text = (isPercussion) ? + "percussion" : "melodic"; + if(missing.insert(bank).second) + { + hooks.onDebugMessage(hooks.onDebugMessage_userData, + "[%i] Playing missing %s MIDI bank %i (patch %i)", + channel, text, (bank & ~static_cast(OPL3::PercussionTag)), midiins); + } + } + + //Or fall back to first bank + if((ains->flags & adlinsdata::Flag_NoSound) != 0) + { + OPL3::BankMap::iterator b = m_synth.m_insBanks.find(bank & OPL3::PercussionTag); + if(b != m_synth.m_insBanks.end()) + bnk = &b->second; if(bnk) ains = &bnk->ins[midiins]; } - /* - if(MidCh%16 == 9 || (midiins != 32 && midiins != 46 && midiins != 48 && midiins != 50)) - break; // HACK - if(midiins == 46) vol = (vol*7)/10; // HACK - if(midiins == 48 || midiins == 50) vol /= 4; // HACK - */ - //if(midiins == 56) vol = vol*6/10; // HACK - //int meta = banks[opl.AdlBank][midiins]; + const int veloffset = ains->midi_velocity_offset; + velocity = (uint8_t)std::min(127, std::max(1, (int)velocity + veloffset)); - int16_t tone = note; - - if(!isPercussion && !isXgPercussion && (bank > 0)) // For non-zero banks + int32_t tone = note; + if(!isPercussion && (bank > 0)) // For non-zero banks { if(ains->flags & adlinsdata::Flag_NoSound) { - if(hooks.onDebugMessage) + if(hooks.onDebugMessage && caugh_missing_instruments.insert(static_cast(midiins)).second) { - if(caugh_missing_instruments.insert(static_cast(midiins)).second) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Caugh a blank instrument %i (offset %i) in the MIDI bank %u", channel, Ch[channel].patch, midiins, bank); + hooks.onDebugMessage(hooks.onDebugMessage_userData, + "[%i] Caught a blank instrument %i (offset %i) in the MIDI bank %u", + channel, m_midiChannels[channel].patch, midiins, bank); } bank = 0; midiins = midiChan.patch; @@ -1094,12 +418,13 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) } //uint16_t i[2] = { ains->adlno1, ains->adlno2 }; + bool is_2op = !(ains->flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)); bool pseudo_4op = ains->flags & adlinsdata::Flag_Pseudo4op; #ifndef __WATCOMC__ MIDIchannel::NoteInfo::Phys voices[MIDIchannel::NoteInfo::MaxNumPhysChans] = { {0, ains->adl[0], false}, - {0, ains->adl[1], pseudo_4op} + {0, (!is_2op) ? ains->adl[1] : ains->adl[0], pseudo_4op} }; #else /* Unfortunately, WatCom can't brace-initialize structure that incluses structure fields */ MIDIchannel::NoteInfo::Phys voices[MIDIchannel::NoteInfo::MaxNumPhysChans]; @@ -1107,20 +432,34 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) voices[0].ains = ains->adl[0]; voices[0].pseudo4op = false; voices[1].chip_chan = 0; - voices[1].ains = ains->adl[1]; + voices[1].ains = (!is_2op) ? ains->adl[1] : ains->adl[0]; voices[1].pseudo4op = pseudo_4op; #endif /* __WATCOMC__ */ - if((opl.AdlPercussionMode == 1) && PercussionMap[midiins & 0xFF]) + if((m_synth.m_rhythmMode == 1) && PercussionMap[midiins & 0xFF]) voices[1] = voices[0];//i[1] = i[0]; + bool isBlankNote = (ains->flags & adlinsdata::Flag_NoSound) != 0; + if(hooks.onDebugMessage) { - if((ains->flags & adlinsdata::Flag_NoSound) && - caugh_missing_instruments.insert(static_cast(midiins)).second) + if(isBlankNote && caugh_missing_instruments.insert(static_cast(midiins)).second) hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing instrument %i", channel, midiins); } + if(isBlankNote) + { + // Don't even try to play the blank instrument! But, insert the dummy note. + std::pair + dummy = midiChan.activenotes_insert(note); + dummy.first->isBlank = true; + dummy.first->ains = NULL; + dummy.first->chip_channels_count = 0; + // Record the last note on MIDI channel as source of portamento + midiChan.portamentoSource = static_cast(note); + return false; + } + // Allocate AdLib channel (the physical sound channel for the note) int32_t adlchannel[MIDIchannel::NoteInfo::MaxNumPhysChans] = { -1, -1 }; @@ -1137,25 +476,25 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) int32_t c = -1; int32_t bs = -0x7FFFFFFFl; - for(size_t a = 0; a < (size_t)opl.NumChannels; ++a) + for(size_t a = 0; a < (size_t)m_synth.m_numChannels; ++a) { if(ccount == 1 && static_cast(a) == adlchannel[0]) continue; // ^ Don't use the same channel for primary&secondary - if(voices[0].ains == voices[1].ains || pseudo_4op/*i[0] == i[1] || pseudo_4op*/) + if(is_2op || pseudo_4op) { // Only use regular channels - uint8_t expected_mode = 0; + uint32_t expected_mode = 0; - if(opl.AdlPercussionMode == 1) + if(m_synth.m_rhythmMode) { - if(cmf_percussion_mode) + if(m_cmfPercussionMode) expected_mode = channel < 11 ? 0 : (3 + channel - 11); // CMF else expected_mode = PercussionMap[midiins & 0xFF]; } - if(opl.four_op_category[a] != expected_mode) + if(m_synth.m_channelCategory[a] != expected_mode) continue; } else @@ -1163,7 +502,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(ccount == 0) { // Only use four-op master channels - if(opl.four_op_category[a] != 1) + if(m_synth.m_channelCategory[a] != OPL3::ChanCat_4op_Master) continue; } else @@ -1174,7 +513,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) } } - int64_t s = CalculateAdlChannelGoodness(a, voices[ccount], channel); + int64_t s = calculateChipChannelGoodness(a, voices[ccount]); if(s > bs) { bs = (int32_t)s; // Best candidate wins @@ -1191,7 +530,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) continue; // Could not play this note. Ignore it. } - PrepareAdlChannelForNewNote(static_cast(c), voices[ccount]); + prepareChipChannelForNewNote(static_cast(c), voices[ccount]); adlchannel[ccount] = c; } @@ -1204,16 +543,39 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) //if(hooks.onDebugMessage) // hooks.onDebugMessage(hooks.onDebugMessage_userData, "i1=%d:%d, i2=%d:%d", i[0],adlchannel[0], i[1],adlchannel[1]); + if(midiChan.softPedal) // Apply Soft Pedal level reducing + velocity = static_cast(std::floor(static_cast(velocity) * 0.8f)); + // Allocate active note for MIDI channel std::pair ir = midiChan.activenotes_insert(note); ir.first->vol = velocity; ir.first->vibrato = midiChan.noteAftertouch[note]; - ir.first->tone = tone; + ir.first->noteTone = static_cast(tone); + ir.first->currentTone = tone; + ir.first->glideRate = HUGE_VAL; ir.first->midiins = midiins; + ir.first->isPercussion = isPercussion; + ir.first->isBlank = isBlankNote; ir.first->ains = ains; ir.first->chip_channels_count = 0; + int8_t currentPortamentoSource = midiChan.portamentoSource; + double currentPortamentoRate = midiChan.portamentoRate; + bool portamentoEnable = + midiChan.portamentoEnable && currentPortamentoRate != HUGE_VAL && !isPercussion; + // Record the last note on MIDI channel as source of portamento + midiChan.portamentoSource = static_cast(note); + // midiChan.portamentoSource = portamentoEnable ? (int8_t)note : (int8_t)-1; + + // Enable gliding on portamento note + if (portamentoEnable && currentPortamentoSource >= 0) + { + ir.first->currentTone = currentPortamentoSource; + ir.first->glideRate = currentPortamentoRate; + ++midiChan.gliding_note_count; + } + for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) { int32_t c = adlchannel[ccount]; @@ -1222,21 +584,34 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) uint16_t chipChan = static_cast(adlchannel[ccount]); ir.first->phys_ensure_find_or_create(chipChan)->assign(voices[ccount]); } - NoteUpdate(channel, ir.first, Upd_All | Upd_Patch); + + noteUpdate(channel, ir.first, Upd_All | Upd_Patch); + + for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) + { + int32_t c = adlchannel[ccount]; + if(c < 0) + continue; + m_chipChannels[c].recent_ins = voices[ccount]; + m_chipChannels[c].addAge(0); + } + return true; } void MIDIplay::realTime_NoteOff(uint8_t channel, uint8_t note) { - channel = channel % 16; - NoteOff(channel, note); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + noteOff(channel, note); } void MIDIplay::realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal) { - channel = channel % 16; - MIDIchannel &chan = Ch[channel]; - MIDIchannel::activenoteiterator i = Ch[channel].activenotes_find(note); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + MIDIchannel &chan = m_midiChannels[channel]; + MIDIchannel::activenoteiterator i = m_midiChannels[channel].activenotes_find(note); if(i) { i->vibrato = atVal; @@ -1255,87 +630,100 @@ void MIDIplay::realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t at void MIDIplay::realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal) { - channel = channel % 16; - Ch[channel].aftertouch = atVal; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].aftertouch = atVal; } void MIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t value) { - channel = channel % 16; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; switch(type) { case 1: // Adjust vibrato //UI.PrintLn("%u:vibrato %d", MidCh,value); - Ch[channel].vibrato = value; + m_midiChannels[channel].vibrato = value; break; case 0: // Set bank msb (GM bank) - Ch[channel].bank_msb = value; - Ch[channel].is_xg_percussion = isXgPercChannel(Ch[channel].bank_msb, Ch[channel].bank_lsb); + m_midiChannels[channel].bank_msb = value; + if((m_synthMode & Mode_GS) == 0)// Don't use XG drums on GS synth mode + m_midiChannels[channel].is_xg_percussion = isXgPercChannel(m_midiChannels[channel].bank_msb, m_midiChannels[channel].bank_lsb); break; case 32: // Set bank lsb (XG bank) - Ch[channel].bank_lsb = value; - Ch[channel].is_xg_percussion = isXgPercChannel(Ch[channel].bank_msb, Ch[channel].bank_lsb); + m_midiChannels[channel].bank_lsb = value; + if((m_synthMode & Mode_GS) == 0)// Don't use XG drums on GS synth mode + m_midiChannels[channel].is_xg_percussion = isXgPercChannel(m_midiChannels[channel].bank_msb, m_midiChannels[channel].bank_lsb); break; case 5: // Set portamento msb - Ch[channel].portamento = static_cast((Ch[channel].portamento & 0x7F) | (value << 7)); - //UpdatePortamento(MidCh); + m_midiChannels[channel].portamento = static_cast((m_midiChannels[channel].portamento & 0x007F) | (value << 7)); + updatePortamento(channel); break; case 37: // Set portamento lsb - Ch[channel].portamento = (Ch[channel].portamento & 0x3F80) | (value); - //UpdatePortamento(MidCh); + m_midiChannels[channel].portamento = static_cast((m_midiChannels[channel].portamento & 0x3F80) | (value)); + updatePortamento(channel); break; case 65: // Enable/disable portamento - // value >= 64 ? enabled : disabled - //UpdatePortamento(MidCh); + m_midiChannels[channel].portamentoEnable = value >= 64; + updatePortamento(channel); break; case 7: // Change volume - Ch[channel].volume = value; - NoteUpdate_All(channel, Upd_Volume); + m_midiChannels[channel].volume = value; + noteUpdateAll(channel, Upd_Volume); break; case 74: // Change brightness - Ch[channel].brightness = value; - NoteUpdate_All(channel, Upd_Volume); + m_midiChannels[channel].brightness = value; + noteUpdateAll(channel, Upd_Volume); break; case 64: // Enable/disable sustain - Ch[channel].sustain = value; - if(!value) KillSustainingNotes(channel); + m_midiChannels[channel].sustain = (value >= 64); + if(!m_midiChannels[channel].sustain) + killSustainingNotes(channel, -1, AdlChannel::LocationData::Sustain_Pedal); + break; + + case 66: // Enable/disable sostenuto + if(value >= 64) //Find notes and mark them as sostenutoed + markSostenutoNotes(channel); + else + killSustainingNotes(channel, -1, AdlChannel::LocationData::Sustain_Sostenuto); + break; + + case 67: // Enable/disable soft-pedal + m_midiChannels[channel].softPedal = (value >= 64); break; case 11: // Change expression (another volume factor) - Ch[channel].expression = value; - NoteUpdate_All(channel, Upd_Volume); + m_midiChannels[channel].expression = value; + noteUpdateAll(channel, Upd_Volume); break; case 10: // Change panning - Ch[channel].panning = 0x00; - if(value < 64 + 32) Ch[channel].panning |= OPL_PANNING_LEFT; - if(value >= 64 - 32) Ch[channel].panning |= OPL_PANNING_RIGHT; + m_midiChannels[channel].panning = value; - NoteUpdate_All(channel, Upd_Pan); + noteUpdateAll(channel, Upd_Pan); break; case 121: // Reset all controllers - Ch[channel].resetAllControllers(); - //UpdatePortamento(MidCh); - NoteUpdate_All(channel, Upd_Pan + Upd_Volume + Upd_Pitch); + m_midiChannels[channel].resetAllControllers(); + noteUpdateAll(channel, Upd_Pan + Upd_Volume + Upd_Pitch); // Kill all sustained notes - KillSustainingNotes(channel); + killSustainingNotes(channel, -1, AdlChannel::LocationData::Sustain_ANY); break; case 120: // All sounds off - NoteUpdate_All(channel, Upt_OffMute); + noteUpdateAll(channel, Upd_OffMute); break; case 123: // All notes off - NoteUpdate_All(channel, Upd_Off); + noteUpdateAll(channel, Upd_Off); break; case 91: @@ -1354,38 +742,39 @@ void MIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t value) break; // Phaser effect depth. We don't do. case 98: - Ch[channel].lastlrpn = value; - Ch[channel].nrpn = true; + m_midiChannels[channel].lastlrpn = value; + m_midiChannels[channel].nrpn = true; break; case 99: - Ch[channel].lastmrpn = value; - Ch[channel].nrpn = true; + m_midiChannels[channel].lastmrpn = value; + m_midiChannels[channel].nrpn = true; break; case 100: - Ch[channel].lastlrpn = value; - Ch[channel].nrpn = false; + m_midiChannels[channel].lastlrpn = value; + m_midiChannels[channel].nrpn = false; break; case 101: - Ch[channel].lastmrpn = value; - Ch[channel].nrpn = false; + m_midiChannels[channel].lastmrpn = value; + m_midiChannels[channel].nrpn = false; break; case 113: break; // Related to pitch-bender, used by missimp.mid in Duke3D case 6: - SetRPN(channel, value, true); + setRPN(channel, value, true); break; case 38: - SetRPN(channel, value, false); + setRPN(channel, value, false); break; case 103: - cmf_percussion_mode = (value != 0); + if(m_synth.m_musicMode == OPL3::MODE_CMF) + m_cmfPercussionMode = (value != 0); break; // CMF (ctrl 0x67) rhythm mode default: @@ -1396,71 +785,338 @@ void MIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t value) void MIDIplay::realTime_PatchChange(uint8_t channel, uint8_t patch) { - channel = channel % 16; - Ch[channel].patch = patch; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].patch = patch; } void MIDIplay::realTime_PitchBend(uint8_t channel, uint16_t pitch) { - channel = channel % 16; - Ch[channel].bend = int(pitch) - 8192; - NoteUpdate_All(channel, Upd_Pitch); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bend = int(pitch) - 8192; + noteUpdateAll(channel, Upd_Pitch); } void MIDIplay::realTime_PitchBend(uint8_t channel, uint8_t msb, uint8_t lsb) { - channel = channel % 16; - Ch[channel].bend = int(lsb) + int(msb) * 128 - 8192; - NoteUpdate_All(channel, Upd_Pitch); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bend = int(lsb) + int(msb) * 128 - 8192; + noteUpdateAll(channel, Upd_Pitch); } void MIDIplay::realTime_BankChangeLSB(uint8_t channel, uint8_t lsb) { - channel = channel % 16; - Ch[channel].bank_lsb = lsb; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bank_lsb = lsb; } void MIDIplay::realTime_BankChangeMSB(uint8_t channel, uint8_t msb) { - channel = channel % 16; - Ch[channel].bank_msb = msb; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bank_msb = msb; } void MIDIplay::realTime_BankChange(uint8_t channel, uint16_t bank) { - channel = channel % 16; - Ch[channel].bank_lsb = uint8_t(bank & 0xFF); - Ch[channel].bank_msb = uint8_t((bank >> 8) & 0xFF); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bank_lsb = uint8_t(bank & 0xFF); + m_midiChannels[channel].bank_msb = uint8_t((bank >> 8) & 0xFF); +} + +void MIDIplay::setDeviceId(uint8_t id) +{ + m_sysExDeviceId = id; +} + +bool MIDIplay::realTime_SysEx(const uint8_t *msg, size_t size) +{ + if(size < 4 || msg[0] != 0xF0 || msg[size - 1] != 0xF7) + return false; + + unsigned manufacturer = msg[1]; + unsigned dev = msg[2]; + msg += 3; + size -= 4; + + switch(manufacturer) + { + default: + break; + case Manufacturer_UniversalNonRealtime: + case Manufacturer_UniversalRealtime: + return doUniversalSysEx( + dev, manufacturer == Manufacturer_UniversalRealtime, msg, size); + case Manufacturer_Roland: + return doRolandSysEx(dev, msg, size); + case Manufacturer_Yamaha: + return doYamahaSysEx(dev, msg, size); + } + + return false; +} + +bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size) +{ + bool devicematch = dev == 0x7F || dev == m_sysExDeviceId; + if(size < 2 || !devicematch) + return false; + + unsigned address = + (((unsigned)data[0] & 0x7F) << 8) | + (((unsigned)data[1] & 0x7F)); + data += 2; + size -= 2; + + switch(((unsigned)realtime << 16) | address) + { + case (0 << 16) | 0x0901: // GM System On + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System On"); + m_synthMode = Mode_GM; + realTime_ResetState(); + return true; + case (0 << 16) | 0x0902: // GM System Off + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System Off"); + m_synthMode = Mode_XG;//TODO: TEMPORARY, make something RIGHT + realTime_ResetState(); + return true; + case (1 << 16) | 0x0401: // MIDI Master Volume + if(size != 2) + break; + unsigned volume = + (((unsigned)data[0] & 0x7F)) | + (((unsigned)data[1] & 0x7F) << 7); + m_masterVolume = static_cast(volume >> 7); + for(size_t ch = 0; ch < m_midiChannels.size(); ch++) + noteUpdateAll(uint16_t(ch), Upd_Volume); + return true; + } + + return false; +} + +bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) +{ + bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; + if(size < 6 || !devicematch) + return false; + + unsigned model = data[0] & 0x7F; + unsigned mode = data[1] & 0x7F; + unsigned checksum = data[size - 1] & 0x7F; + data += 2; + size -= 3; + +#if !defined(ADLMIDI_SKIP_ROLAND_CHECKSUM) + { + unsigned checkvalue = 0; + for(size_t i = 0; i < size; ++i) + checkvalue += data[i] & 0x7F; + checkvalue = (128 - (checkvalue & 127)) & 127; + if(checkvalue != checksum) + { + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught invalid roland SysEx message!"); + return false; + } + } +#endif + + unsigned address = + (((unsigned)data[0] & 0x7F) << 16) | + (((unsigned)data[1] & 0x7F) << 8) | + (((unsigned)data[2] & 0x7F)); + unsigned target_channel = 0; + + /* F0 41 10 42 12 40 00 7F 00 41 F7 */ + + if((address & 0xFFF0FF) == 0x401015) // Turn channel 1 into percussion + { + address = 0x401015; + target_channel = data[1] & 0x0F; + } + + data += 3; + size -= 3; + + if(mode != RolandMode_Send) // don't have MIDI-Out reply ability + return false; + + // Mode Set + // F0 {41 10 42 12} {40 00 7F} {00 41} F7 + + // Custom drum channels + // F0 {41 10 42 12} {40 1 15} { } F7 + + switch((model << 24) | address) + { + case (RolandModel_GS << 24) | 0x00007F: // System Mode Set + { + if(size != 1 || (dev & 0xF0) != 0x10) + break; + unsigned mode = data[0] & 0x7F; + ADL_UNUSED(mode);//TODO: Hook this correctly! + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland System Mode Set: %02X", mode); + m_synthMode = Mode_GS; + realTime_ResetState(); + return true; + } + case (RolandModel_GS << 24) | 0x40007F: // Mode Set + { + if(size != 1 || (dev & 0xF0) != 0x10) + break; + unsigned value = data[0] & 0x7F; + ADL_UNUSED(value);//TODO: Hook this correctly! + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland Mode Set: %02X", value); + m_synthMode = Mode_GS; + realTime_ResetState(); + return true; + } + case (RolandModel_GS << 24) | 0x401015: // Percussion channel + { + if(size != 1 || (dev & 0xF0) != 0x10) + break; + if(m_midiChannels.size() < 16) + break; + unsigned value = data[0] & 0x7F; + const uint8_t channels_map[16] = + { + 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15 + }; + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, + "SysEx: Caught Roland Percussion set: %02X on channel %u (from %X)", + value, channels_map[target_channel], target_channel); + m_midiChannels[channels_map[target_channel]].is_xg_percussion = ((value == 0x01)) || ((value == 0x02)); + return true; + } + } + + return false; +} + +bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) +{ + bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; + if(size < 1 || !devicematch) + return false; + + unsigned model = data[0] & 0x7F; + ++data; + --size; + + switch((model << 8) | (dev & 0xF0)) + { + case (YamahaModel_XG << 8) | 0x10: // parameter change + { + if(size < 3) + break; + + unsigned address = + (((unsigned)data[0] & 0x7F) << 16) | + (((unsigned)data[1] & 0x7F) << 8) | + (((unsigned)data[2] & 0x7F)); + data += 3; + size -= 3; + + switch(address) + { + case 0x00007E: // XG System On + if(size != 1) + break; + unsigned value = data[0] & 0x7F; + ADL_UNUSED(value);//TODO: Hook this correctly! + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Yamaha XG System On: %02X", value); + m_synthMode = Mode_XG; + realTime_ResetState(); + return true; + } + + break; + } + } + + return false; } void MIDIplay::realTime_panic() { - Panic(); - KillSustainingNotes(-1, -1); + panic(); + killSustainingNotes(-1, -1, AdlChannel::LocationData::Sustain_ANY); } -void MIDIplay::AudioTick(uint32_t chipId, uint32_t /*rate*/) +void MIDIplay::realTime_deviceSwitch(size_t track, const char *data, size_t length) +{ + const std::string indata(data, length); + m_currentMidiDevice[track] = chooseDevice(indata); +} + +size_t MIDIplay::realTime_currentDevice(size_t track) +{ + if(m_currentMidiDevice.empty()) + return 0; + return m_currentMidiDevice[track]; +} + +void MIDIplay::realTime_rawOPL(uint8_t reg, uint8_t value) +{ + if((reg & 0xF0) == 0xC0) + value |= 0x30; + //std::printf("OPL poke %02X, %02X\n", reg, value); + //std::fflush(stdout); + m_synth.writeReg(0, reg, value); +} + +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) +void MIDIplay::AudioTick(uint32_t chipId, uint32_t rate) { if(chipId != 0) // do first chip ticks only return; - /*uint32_t tickNumber = */m_audioTickCounter++; -} + uint32_t tickNumber = m_audioTickCounter++; + double timeDelta = 1.0 / rate; -void MIDIplay::NoteUpdate(uint16_t MidCh, + enum { portamentoInterval = 32 }; // for efficiency, set rate limit on pitch updates + + if(tickNumber % portamentoInterval == 0) + { + double portamentoDelta = timeDelta * portamentoInterval; + updateGlide(portamentoDelta); + } +} +#endif + +void MIDIplay::noteUpdate(size_t midCh, MIDIplay::MIDIchannel::activenoteiterator i, unsigned props_mask, int32_t select_adlchn) { MIDIchannel::NoteInfo &info = *i; - const int16_t tone = info.tone; + const int16_t noteTone = info.noteTone; + const double currentTone = info.currentTone; const uint8_t vol = info.vol; const int midiins = static_cast(info.midiins); const adlinsdata2 &ains = *info.ains; AdlChannel::Location my_loc; - my_loc.MidCh = MidCh; + my_loc.MidCh = static_cast(midCh); my_loc.note = info.note; + if(info.isBlank) + { + if(props_mask & Upd_Off) + m_midiChannels[midCh].activenotes_erase(i); + return; + } + for(unsigned ccount = 0, ctotal = info.chip_channels_count; ccount < ctotal; ccount++) { const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount]; @@ -1470,14 +1126,14 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, if(props_mask & Upd_Patch) { - opl.Patch(c, ins.ains); - AdlChannel::LocationData *d = ch[c].users_find_or_create(my_loc); + m_synth.setPatch(c, ins.ains); + AdlChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); if(d) // inserts if necessary { - d->sustained = false; - d->vibdelay = 0; + d->sustained = AdlChannel::LocationData::Sustain_None; + d->vibdelay_us = 0; d->fixed_sustain = (ains.ms_sound_kon == static_cast(adlNoteOnMaxTime)); - d->kon_time_until_neglible = ains.ms_sound_kon; + d->kon_time_until_neglible_us = 1000 * ains.ms_sound_kon; d->ins = ins; } } @@ -1486,34 +1142,35 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, for(unsigned ccount = 0; ccount < info.chip_channels_count; ccount++) { const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount]; - uint16_t c = ins.chip_chan; + uint16_t c = ins.chip_chan; + uint16_t c_slave = info.chip_channels[1].chip_chan; if(select_adlchn >= 0 && c != select_adlchn) continue; if(props_mask & Upd_Off) // note off { - if(Ch[MidCh].sustain == 0) + if(!m_midiChannels[midCh].sustain) { - AdlChannel::LocationData *k = ch[c].users_find(my_loc); - - if(k) - ch[c].users_erase(k); + AdlChannel::LocationData *k = m_chipChannels[c].users_find(my_loc); + bool do_erase_user = (k && ((k->sustained & AdlChannel::LocationData::Sustain_Sostenuto) == 0)); + if(do_erase_user) + m_chipChannels[c].users_erase(k); if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, tone, midiins, 0, 0.0); + hooks.onNote(hooks.onNote_userData, c, noteTone, midiins, 0, 0.0); - if(ch[c].users_empty()) + if(do_erase_user && m_chipChannels[c].users_empty()) { - opl.NoteOff(c); + m_synth.noteOff(c); if(props_mask & Upd_Mute) // Mute the note { - opl.Touch_Real(c, 0); - ch[c].koff_time_until_neglible = 0; + m_synth.touchNote(c, 0); + m_chipChannels[c].koff_time_until_neglible_us = 0; } else { - ch[c].koff_time_until_neglible = ains.ms_sound_koff; + m_chipChannels[c].koff_time_until_neglible_us = 1000 * int64_t(ains.ms_sound_koff); } } } @@ -1521,11 +1178,11 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, { // Sustain: Forget about the note, but don't key it off. // Also will avoid overwriting it very soon. - AdlChannel::LocationData *d = ch[c].users_find_or_create(my_loc); + AdlChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); if(d) - d->sustained = true; // note: not erased! + d->sustained |= AdlChannel::LocationData::Sustain_Pedal; // note: not erased! if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, tone, midiins, -1, 0.0); + hooks.onNote(hooks.onNote_userData, c, noteTone, midiins, -1, 0.0); } info.phys_erase_at(&ins); // decrements channel count @@ -1534,13 +1191,13 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, } if(props_mask & Upd_Pan) - opl.Pan(c, Ch[MidCh].panning); + m_synth.setPan(c, m_midiChannels[midCh].panning); if(props_mask & Upd_Volume) { - uint32_t volume; - bool is_percussion = (MidCh == 9) || Ch[MidCh].is_xg_percussion; - uint8_t brightness = is_percussion ? 127 : Ch[MidCh].brightness; + uint_fast32_t volume; + bool is_percussion = (midCh == 9) || m_midiChannels[midCh].is_xg_percussion; + uint_fast32_t brightness = is_percussion ? 127 : m_midiChannels[midCh].brightness; if(!m_setup.fullRangeBrightnessCC74) { @@ -1551,12 +1208,12 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, brightness *= 2; } - switch(opl.m_volumeScale) + switch(m_synth.m_volumeScale) { - + default: case OPL3::VOLUME_Generic: { - volume = vol * Ch[MidCh].volume * Ch[MidCh].expression; + volume = vol * m_masterVolume * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression; /* If the channel has arpeggio, the effective volume of * *this* instrument is actually lower due to timesharing. @@ -1567,77 +1224,73 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, */ //volume = (int)(volume * std::sqrt( (double) ch[c].users.size() )); - // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) - volume = volume > 8725 ? static_cast(std::log(static_cast(volume)) * 11.541561 + (0.5 - 104.22845)) : 0; - // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) - //opl.Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); - - opl.Touch_Real(c, volume, brightness); - //opl.Touch(c, volume); + // The formula below: SOLVE(V=127^4 * 2^( (A-63.49999) / 8), A) + volume = volume > (8725 * 127) ? static_cast(std::log(static_cast(volume)) * 11.541560327111707 - 1.601379199767093e+02) : 0; + // The incorrect formula below: SOLVE(V=127^4 * (2^(A/63)-1), A) + //opl.Touch_Real(c, volume>(11210*127) ? 91.61112 * std::log((4.8819E-7/127)*volume + 1.0)+0.5 : 0); } break; case OPL3::VOLUME_NATIVE: { - volume = vol * Ch[MidCh].volume * Ch[MidCh].expression; - volume = volume * 127 / (127 * 127 * 127) / 2; - opl.Touch_Real(c, volume, brightness); + volume = vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression; + // volume = volume * m_masterVolume / (127 * 127 * 127) / 2; + volume = (volume * m_masterVolume) / 4096766; } break; case OPL3::VOLUME_DMX: { - volume = 2 * ((Ch[MidCh].volume * Ch[MidCh].expression) * 127 / 16129) + 1; + volume = 2 * (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 16129) + 1; //volume = 2 * (Ch[MidCh].volume) + 1; volume = (DMX_volume_mapping_table[(vol < 128) ? vol : 127] * volume) >> 9; - opl.Touch_Real(c, volume, brightness); } break; case OPL3::VOLUME_APOGEE: { - volume = ((Ch[MidCh].volume * Ch[MidCh].expression) * 127 / 16129); + volume = (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 16129); volume = ((64 * (vol + 0x80)) * volume) >> 15; //volume = ((63 * (vol + 0x80)) * Ch[MidCh].volume) >> 15; - opl.Touch_Real(c, volume, brightness); } break; case OPL3::VOLUME_9X: { - //volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume /** Ch[MidCh].expression*/) * 127 / 16129 /*2048383*/) >> 2)]; - volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume * Ch[MidCh].expression) * 127 / 2048383) >> 2)]; + //volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume /** Ch[MidCh].expression*/) * m_masterVolume / 16129 /*2048383*/) >> 2)]; + volume = 63 - W9X_volume_mapping_table[((vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 2048383) >> 2)]; //volume = W9X_volume_mapping_table[vol >> 2] + volume; - opl.Touch_Real(c, volume, brightness); } break; } + m_synth.touchNote(c, static_cast(volume), static_cast(brightness)); + /* DEBUG ONLY!!! - static uint32_t max = 0; + static uint32_t max = 0; - if(volume == 0) - max = 0; + if(volume == 0) + max = 0; - if(volume > max) - max = volume; + if(volume > max) + max = volume; - printf("%d\n", max); - fflush(stdout); - */ + printf("%d\n", max); + fflush(stdout); + */ } if(props_mask & Upd_Pitch) { - AdlChannel::LocationData *d = ch[c].users_find(my_loc); + AdlChannel::LocationData *d = m_chipChannels[c].users_find(my_loc); // Don't bend a sustained note - if(!d || !d->sustained) + if(!d || (d->sustained == AdlChannel::LocationData::Sustain_None)) { - double midibend = Ch[MidCh].bend * Ch[MidCh].bendsense; + double midibend = m_midiChannels[midCh].bend * m_midiChannels[midCh].bendsense; double bend = midibend + ins.ains.finetune; double phase = 0.0; - uint8_t vibrato = std::max(Ch[MidCh].vibrato, Ch[MidCh].aftertouch); + uint8_t vibrato = std::max(m_midiChannels[midCh].vibrato, m_midiChannels[midCh].aftertouch); vibrato = std::max(vibrato, i->vibrato); if((ains.flags & adlinsdata::Flag_Pseudo4op) && ins.pseudo4op) @@ -1645,359 +1298,36 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, phase = ains.voice2_fine_tune;//0.125; // Detune the note slightly (this is what Doom does) } - if(vibrato && (!d || d->vibdelay >= Ch[MidCh].vibdelay)) - bend += static_cast(vibrato) * Ch[MidCh].vibdepth * std::sin(Ch[MidCh].vibpos); + if(vibrato && (!d || d->vibdelay_us >= m_midiChannels[midCh].vibdelay_us)) + bend += static_cast(vibrato) * m_midiChannels[midCh].vibdepth * std::sin(m_midiChannels[midCh].vibpos); -#ifdef ADLMIDI_USE_DOSBOX_OPL -# define BEND_COEFFICIENT 172.00093 -#else -# define BEND_COEFFICIENT 172.4387 -#endif - opl.NoteOn(c, BEND_COEFFICIENT * std::exp(0.057762265 * (static_cast(tone) + bend + phase))); +#define BEND_COEFFICIENT 172.4387 + m_synth.noteOn(c, c_slave, BEND_COEFFICIENT * std::exp(0.057762265 * (currentTone + bend + phase))); #undef BEND_COEFFICIENT if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, tone, midiins, vol, midibend); + hooks.onNote(hooks.onNote_userData, c, noteTone, midiins, vol, midibend); } } } if(info.chip_channels_count == 0) - Ch[MidCh].activenotes_erase(i); + { + if(i->glideRate != HUGE_VAL) + --m_midiChannels[midCh].gliding_note_count; + m_midiChannels[midCh].activenotes_erase(i); + } } -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -bool MIDIplay::ProcessEventsNew(bool isSeek) +void MIDIplay::noteUpdateAll(size_t midCh, unsigned props_mask) { - if(CurrentPositionNew.track.size() == 0) - atEnd = true;//No MIDI track data to play - if(atEnd) - return false;//No more events in the queue - - loopEnd = false; - const size_t TrackCount = CurrentPositionNew.track.size(); - const PositionNew RowBeginPosition(CurrentPositionNew); - -#ifdef DEBUG_TIME_CALCULATION - double maxTime = 0.0; -#endif - - for(size_t tk = 0; tk < TrackCount; ++tk) + for(MIDIchannel::activenoteiterator + i = m_midiChannels[midCh].activenotes_begin(); i;) { - PositionNew::TrackInfo &track = CurrentPositionNew.track[tk]; - if((track.status >= 0) && (track.delay <= 0)) - { - //Check is an end of track has been reached - if(track.pos == trackDataNew[tk].end()) - { - track.status = -1; - break; - } - - // Handle event - for(size_t i = 0; i < track.pos->events.size(); i++) - { - const MidiEvent &evt = track.pos->events[i]; -#ifdef ENABLE_BEGIN_SILENCE_SKIPPING - if(!CurrentPositionNew.began && (evt.type == MidiEvent::T_NOTEON)) - CurrentPositionNew.began = true; -#endif - if(isSeek && (evt.type == MidiEvent::T_NOTEON)) - continue; - HandleEvent(tk, evt, track.status); - if(loopEnd) - break;//Stop event handling on catching loopEnd event! - } - -#ifdef DEBUG_TIME_CALCULATION - if(maxTime < track.pos->time) - maxTime = track.pos->time; -#endif - // Read next event time (unless the track just ended) - if(track.status >= 0) - { - track.delay += track.pos->delay; - track.pos++; - } - } + MIDIchannel::activenoteiterator j(i++); + noteUpdate(midCh, j, props_mask); } - -#ifdef DEBUG_TIME_CALCULATION - std::fprintf(stdout, " \r"); - std::fprintf(stdout, "Time: %10f; Audio: %10f\r", maxTime, CurrentPositionNew.absTimePosition); - std::fflush(stdout); -#endif - - // Find shortest delay from all track - uint64_t shortest = 0; - bool shortest_no = true; - - for(size_t tk = 0; tk < TrackCount; ++tk) - { - PositionNew::TrackInfo &track = CurrentPositionNew.track[tk]; - if((track.status >= 0) && (shortest_no || track.delay < shortest)) - { - shortest = track.delay; - shortest_no = false; - } - } - - //if(shortest > 0) UI.PrintLn("shortest: %ld", shortest); - - // Schedule the next playevent to be processed after that delay - for(size_t tk = 0; tk < TrackCount; ++tk) - CurrentPositionNew.track[tk].delay -= shortest; - - fraction t = shortest * Tempo; - -#ifdef ENABLE_BEGIN_SILENCE_SKIPPING - if(CurrentPositionNew.began) -#endif - CurrentPositionNew.wait += t.value(); - - //if(shortest > 0) UI.PrintLn("Delay %ld (%g)", shortest, (double)t.valuel()); - if(loopStart) - { - LoopBeginPositionNew = RowBeginPosition; - loopStart = false; - } - - if(shortest_no || loopEnd) - { - //Loop if song end or loop end point has reached - loopEnd = false; - shortest = 0; - if(!m_setup.loopingIsEnabled) - { - atEnd = true; //Don't handle events anymore - CurrentPositionNew.wait += postSongWaitDelay;//One second delay until stop playing - return true;//We have caugh end here! - } - CurrentPositionNew = LoopBeginPositionNew; - } - - return true;//Has events in queue } -MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t **pptr, uint8_t *end, int &status) -{ - uint8_t *&ptr = *pptr; - MIDIplay::MidiEvent evt; - - if(ptr + 1 > end) - { - //When track doesn't ends on the middle of event data, it's must be fine - evt.type = MidiEvent::T_SPECIAL; - evt.subtype = MidiEvent::ST_ENDTRACK; - return evt; - } - - unsigned char byte = *(ptr++); - bool ok = false; - - if(byte == MidiEvent::T_SYSEX || byte == MidiEvent::T_SYSEX2)// Ignore SysEx - { - uint64_t length = ReadVarLenEx(pptr, end, ok); - if(!ok || (ptr + length > end)) - { - errorString += "parseEvent: Can't read SysEx event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - ptr += (size_t)length; - return evt; - } - - if(byte == MidiEvent::T_SPECIAL) - { - // Special event FF - uint8_t evtype = *(ptr++); - uint64_t length = ReadVarLenEx(pptr, end, ok); - if(!ok || (ptr + length > end)) - { - errorString += "parseEvent: Can't read Special event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - std::string data(length ? (const char *)ptr : 0, (size_t)length); - ptr += (size_t)length; - - evt.type = byte; - evt.subtype = evtype; - evt.data.insert(evt.data.begin(), data.begin(), data.end()); - -#if 0 /* Print all tempo events */ - if(evt.subtype == MidiEvent::ST_TEMPOCHANGE) - { - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Temp Change: %02X%02X%02X", evt.data[0], evt.data[1], evt.data[2]); - } -#endif - - /* TODO: Store those meta-strings separately and give ability to read them - * by external functions (to display song title and copyright in the player) */ - if(evt.subtype == MidiEvent::ST_COPYRIGHT) - { - if(musCopyright.empty()) - { - musCopyright = std::string((const char *)evt.data.data(), evt.data.size()); - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Music copyright: %s", musCopyright.c_str()); - } - else if(hooks.onDebugMessage) - { - std::string str((const char *)evt.data.data(), evt.data.size()); - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Extra copyright event: %s", str.c_str()); - } - } - else if(evt.subtype == MidiEvent::ST_SQTRKTITLE) - { - if(musTitle.empty()) - { - musTitle = std::string((const char *)evt.data.data(), evt.data.size()); - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Music title: %s", musTitle.c_str()); - } - else if(hooks.onDebugMessage) - { - //TODO: Store track titles and associate them with each track and make API to retreive them - std::string str((const char *)evt.data.data(), evt.data.size()); - musTrackTitles.push_back(str); - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Track title: %s", str.c_str()); - } - } - else if(evt.subtype == MidiEvent::ST_INSTRTITLE) - { - if(hooks.onDebugMessage) - { - std::string str((const char *)evt.data.data(), evt.data.size()); - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Instrument: %s", str.c_str()); - } - } - else if(evt.subtype == MidiEvent::ST_MARKER) - { - //To lower - for(size_t i = 0; i < data.size(); i++) - { - if(data[i] <= 'Z' && data[i] >= 'A') - data[i] = data[i] - ('Z' - 'z'); - } - - if(data == "loopstart") - { - //Return a custom Loop Start event instead of Marker - evt.subtype = MidiEvent::ST_LOOPSTART; - evt.data.clear();//Data is not needed - return evt; - } - - if(data == "loopend") - { - //Return a custom Loop End event instead of Marker - evt.subtype = MidiEvent::ST_LOOPEND; - evt.data.clear();//Data is not needed - return evt; - } - } - - if(evtype == MidiEvent::ST_ENDTRACK) - status = -1;//Finalize track - - return evt; - } - - // Any normal event (80..EF) - if(byte < 0x80) - { - byte = static_cast(status | 0x80); - ptr--; - } - - //Sys Com Song Select(Song #) [0-127] - if(byte == MidiEvent::T_SYSCOMSNGSEL) - { - if(ptr + 1 > end) - { - errorString += "parseEvent: Can't read System Command Song Select event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - evt.type = byte; - evt.data.push_back(*(ptr++)); - return evt; - } - - //Sys Com Song Position Pntr [LSB, MSB] - if(byte == MidiEvent::T_SYSCOMSPOSPTR) - { - if(ptr + 2 > end) - { - errorString += "parseEvent: Can't read System Command Position Pointer event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - evt.type = byte; - evt.data.push_back(*(ptr++)); - evt.data.push_back(*(ptr++)); - return evt; - } - - uint8_t midCh = byte & 0x0F, evType = (byte >> 4) & 0x0F; - status = byte; - evt.channel = midCh; - evt.type = evType; - - switch(evType) - { - case MidiEvent::T_NOTEOFF://2 byte length - case MidiEvent::T_NOTEON: - case MidiEvent::T_NOTETOUCH: - case MidiEvent::T_CTRLCHANGE: - case MidiEvent::T_WHEEL: - if(ptr + 2 > end) - { - errorString += "parseEvent: Can't read regular 2-byte event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - - evt.data.push_back(*(ptr++)); - evt.data.push_back(*(ptr++)); - - /* TODO: Implement conversion of RSXX's note volumes out of synthesizer */ - /*if((opl.m_musicMode == OPL3::MODE_RSXX) && (evType == MidiEvent::T_NOTEON) && (evt.data[1] != 0)) - { - //NOT WORKING YET - evt.type = MidiEvent::T_NOTETOUCH; - } - else */if((evType == MidiEvent::T_NOTEON) && (evt.data[1] == 0)) - { - evt.type = MidiEvent::T_NOTEOFF; // Note ON with zero velocity is Note OFF! - } //111'th loopStart controller (RPG Maker and others) - else if((evType == MidiEvent::T_CTRLCHANGE) && (evt.data[0] == 111)) - { - //Change event type to custom Loop Start event and clear data - evt.type = MidiEvent::T_SPECIAL; - evt.subtype = MidiEvent::ST_LOOPSTART; - evt.data.clear(); - } - - return evt; - case MidiEvent::T_PATCHCHANGE://1 byte length - case MidiEvent::T_CHANAFTTOUCH: - if(ptr + 1 > end) - { - errorString += "parseEvent: Can't read regular 1-byte event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - evt.data.push_back(*(ptr++)); - return evt; - } - - return evt; -} -#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ - const std::string &MIDIplay::getErrorString() { return errorStringOut; @@ -2008,182 +1338,33 @@ void MIDIplay::setErrorString(const std::string &err) errorStringOut = err; } -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -void MIDIplay::HandleEvent(size_t tk, const MIDIplay::MidiEvent &evt, int &status) +int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const { - if(hooks.onEvent) + const AdlChannel &chan = m_chipChannels[c]; + int64_t koff_ms = chan.koff_time_until_neglible_us / 1000; + int64_t s = -koff_ms; + + // Rate channel with a releasing note + if(s < 0 && chan.users_empty()) { - hooks.onEvent(hooks.onEvent_userData, - evt.type, - evt.subtype, - evt.channel, - evt.data.data(), - evt.data.size()); + s -= 40000; + // If it's same instrument, better chance to get it when no free channels + if(chan.recent_ins == ins) + s = (m_synth.m_musicMode == OPL3::MODE_CMF) ? 0 : -koff_ms; + return s; } - if(evt.type == MidiEvent::T_SYSEX || evt.type == MidiEvent::T_SYSEX2) // Ignore SysEx - { - //std::string data( length?(const char*) &TrackData[tk][CurrentPosition.track[tk].ptr]:0, length ); - //UI.PrintLn("SysEx %02X: %u bytes", byte, length/*, data.c_str()*/); - return; - } - - if(evt.type == MidiEvent::T_SPECIAL) - { - // Special event FF - uint8_t evtype = evt.subtype; - uint64_t length = (uint64_t)evt.data.size(); - std::string data(length ? (const char *)evt.data.data() : 0, (size_t)length); - - if(evtype == MidiEvent::ST_ENDTRACK)//End Of Track - { - status = -1; - return; - } - - if(evtype == MidiEvent::ST_TEMPOCHANGE)//Tempo change - { - Tempo = InvDeltaTicks * fraction(ReadBEint(evt.data.data(), evt.data.size())); - return; - } - - if(evtype == MidiEvent::ST_MARKER)//Meta event - { - //Do nothing! :-P - return; - } - - if(evtype == MidiEvent::ST_DEVICESWITCH) - { - current_device[tk] = ChooseDevice(data); - return; - } - - //if(evtype >= 1 && evtype <= 6) - // UI.PrintLn("Meta %d: %s", evtype, data.c_str()); - - //Turn on Loop handling when loop is enabled - if(m_setup.loopingIsEnabled && !invalidLoop) - { - if(evtype == MidiEvent::ST_LOOPSTART) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib - { - loopStart = true; - return; - } - - if(evtype == MidiEvent::ST_LOOPEND) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib - { - loopEnd = true; - return; - } - } - - if(evtype == MidiEvent::ST_RAWOPL) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib - { - uint8_t i = static_cast(data[0]), v = static_cast(data[1]); - if((i & 0xF0) == 0xC0) - v |= 0x30; - //std::printf("OPL poke %02X, %02X\n", i, v); - //std::fflush(stdout); - opl.Poke(0, i, v); - return; - } - - return; - } - - // Any normal event (80..EF) - // if(evt.type < 0x80) - // { - // byte = static_cast(CurrentPosition.track[tk].status | 0x80); - // CurrentPosition.track[tk].ptr--; - // } - - if(evt.type == MidiEvent::T_SYSCOMSNGSEL || - evt.type == MidiEvent::T_SYSCOMSPOSPTR) - return; - - /*UI.PrintLn("@%X Track %u: %02X %02X", - CurrentPosition.track[tk].ptr-1, (unsigned)tk, byte, - TrackData[tk][CurrentPosition.track[tk].ptr]);*/ - uint8_t midCh = evt.channel;//byte & 0x0F, EvType = byte >> 4; - midCh += (uint8_t)current_device[tk]; - status = evt.type; - - switch(evt.type) - { - case MidiEvent::T_NOTEOFF: // Note off - { - uint8_t note = evt.data[0]; - realTime_NoteOff(midCh, note); - break; - } - - case MidiEvent::T_NOTEON: // Note on - { - uint8_t note = evt.data[0]; - uint8_t vol = evt.data[1]; - /*if(*/ realTime_NoteOn(midCh, note, vol); /*)*/ - //CurrentPosition.began = true; - break; - } - - case MidiEvent::T_NOTETOUCH: // Note touch - { - uint8_t note = evt.data[0]; - uint8_t vol = evt.data[1]; - realTime_NoteAfterTouch(midCh, note, vol); - break; - } - - case MidiEvent::T_CTRLCHANGE: // Controller change - { - uint8_t ctrlno = evt.data[0]; - uint8_t value = evt.data[1]; - realTime_Controller(midCh, ctrlno, value); - break; - } - - case MidiEvent::T_PATCHCHANGE: // Patch change - realTime_PatchChange(midCh, evt.data[0]); - break; - - case MidiEvent::T_CHANAFTTOUCH: // Channel after-touch - { - // TODO: Verify, is this correct action? - uint8_t vol = evt.data[0]; - realTime_ChannelAfterTouch(midCh, vol); - break; - } - - case MidiEvent::T_WHEEL: // Wheel/pitch bend - { - uint8_t a = evt.data[0]; - uint8_t b = evt.data[1]; - realTime_PitchBend(midCh, b, a); - break; - } - } -} -#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ - -int64_t MIDIplay::CalculateAdlChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins, uint16_t) const -{ - int64_t s = -ch[c].koff_time_until_neglible; - // Same midi-instrument = some stability - //if(c == MidCh) s += 4; - for(AdlChannel::LocationData *j = ch[c].users_first; j; j = j->next) + for(AdlChannel::LocationData *j = chan.users_first; j; j = j->next) { - s -= 4000; + s -= 4000000; - if(!j->sustained) - s -= j->kon_time_until_neglible; - else - s -= (j->kon_time_until_neglible / 2); + int64_t kon_ms = j->kon_time_until_neglible_us / 1000; + s -= (j->sustained == AdlChannel::LocationData::Sustain_None) ? + kon_ms : (kon_ms / 2); MIDIchannel::activenoteiterator - k = const_cast(Ch[j->loc.MidCh]).activenotes_find(j->loc.note); + k = const_cast(m_midiChannels[j->loc.MidCh]).activenotes_find(j->loc.note); if(k) { @@ -2192,13 +1373,13 @@ int64_t MIDIplay::CalculateAdlChannelGoodness(size_t c, const MIDIchannel::NoteI { s += 300; // Arpeggio candidate = even better - if(j->vibdelay < 70 - || j->kon_time_until_neglible > 20000) - s += 0; + if(j->vibdelay_us < 70000 + || j->kon_time_until_neglible_us > 20000000) + s += 10; } // Percussion is inferior to melody - s += 50 * (int64_t)(k->midiins / 128); + s += k->isPercussion ? 50 : 0; /* if(k->second.midiins >= 25 && k->second.midiins < 40 @@ -2214,17 +1395,17 @@ int64_t MIDIplay::CalculateAdlChannelGoodness(size_t c, const MIDIchannel::NoteI // increase the score slightly. unsigned n_evacuation_stations = 0; - for(size_t c2 = 0; c2 < static_cast(opl.NumChannels); ++c2) + for(size_t c2 = 0; c2 < static_cast(m_synth.m_numChannels); ++c2) { if(c2 == c) continue; - if(opl.four_op_category[c2] - != opl.four_op_category[c]) continue; + if(m_synth.m_channelCategory[c2] + != m_synth.m_channelCategory[c]) continue; - for(AdlChannel::LocationData *m = ch[c2].users_first; m; m = m->next) + for(AdlChannel::LocationData *m = m_chipChannels[c2].users_first; m; m = m->next) { - if(m->sustained) continue; - if(m->vibdelay >= 200) continue; + if(m->sustained != AdlChannel::LocationData::Sustain_None) continue; + if(m->vibdelay_us >= 200000) continue; if(m->ins != j->ins) continue; n_evacuation_stations += 1; } @@ -2237,26 +1418,26 @@ int64_t MIDIplay::CalculateAdlChannelGoodness(size_t c, const MIDIchannel::NoteI } -void MIDIplay::PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins) +void MIDIplay::prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins) { - if(ch[c].users_empty()) return; // Nothing to do + if(m_chipChannels[c].users_empty()) return; // Nothing to do //bool doing_arpeggio = false; - for(AdlChannel::LocationData *jnext = ch[c].users_first; jnext;) + for(AdlChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) { AdlChannel::LocationData *j = jnext; jnext = jnext->next; - if(!j->sustained) + if(j->sustained == AdlChannel::LocationData::Sustain_None) { // Collision: Kill old note, // UNLESS we're going to do arpeggio MIDIchannel::activenoteiterator i - (Ch[j->loc.MidCh].activenotes_ensure_find(j->loc.note)); + (m_midiChannels[j->loc.MidCh].activenotes_ensure_find(j->loc.note)); // Check if we can do arpeggio. - if((j->vibdelay < 70 - || j->kon_time_until_neglible > 20000) + if((j->vibdelay_us < 70000 + || j->kon_time_until_neglible_us > 20000000) && j->ins == ins) { // Do arpeggio together with this note. @@ -2264,7 +1445,7 @@ void MIDIplay::PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteInfo continue; } - KillOrEvacuate(c, j, i); + killOrEvacuate(c, j, i); // ^ will also erase j from ch[c].users. } } @@ -2272,62 +1453,64 @@ void MIDIplay::PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteInfo // Kill all sustained notes on this channel // Don't keep them for arpeggio, because arpeggio requires // an intact "activenotes" record. This is a design flaw. - KillSustainingNotes(-1, static_cast(c)); + killSustainingNotes(-1, static_cast(c), AdlChannel::LocationData::Sustain_ANY); // Keyoff the channel so that it can be retriggered, // unless the new note will be introduced as just an arpeggio. - if(ch[c].users_empty()) - opl.NoteOff(c); + if(m_chipChannels[c].users_empty()) + m_synth.noteOff(c); } -void MIDIplay::KillOrEvacuate(size_t from_channel, +void MIDIplay::killOrEvacuate(size_t from_channel, AdlChannel::LocationData *j, MIDIplay::MIDIchannel::activenoteiterator i) { + uint32_t maxChannels = ADL_MAX_CHIPS * 18; + // Before killing the note, check if it can be // evacuated to another channel as an arpeggio // instrument. This helps if e.g. all channels // are full of strings and we want to do percussion. // FIXME: This does not care about four-op entanglements. - for(uint32_t c = 0; c < opl.NumChannels; ++c) + for(uint32_t c = 0; c < m_synth.m_numChannels; ++c) { uint16_t cs = static_cast(c); - if(c > std::numeric_limits::max()) + if(c >= maxChannels) break; if(c == from_channel) continue; - if(opl.four_op_category[c] != opl.four_op_category[from_channel]) + if(m_synth.m_channelCategory[c] != m_synth.m_channelCategory[from_channel]) continue; - AdlChannel &adlch = ch[c]; + AdlChannel &adlch = m_chipChannels[c]; if(adlch.users_size == AdlChannel::users_max) continue; // no room for more arpeggio on channel for(AdlChannel::LocationData *m = adlch.users_first; m; m = m->next) { - if(m->vibdelay >= 200 - && m->kon_time_until_neglible < 10000) continue; + if(m->vibdelay_us >= 200000 + && m->kon_time_until_neglible_us < 10000000) continue; if(m->ins != j->ins) continue; if(hooks.onNote) { hooks.onNote(hooks.onNote_userData, (int)from_channel, - i->tone, + i->noteTone, static_cast(i->midiins), 0, 0.0); hooks.onNote(hooks.onNote_userData, (int)c, - i->tone, + i->noteTone, static_cast(i->midiins), i->vol, 0.0); } i->phys_erase(static_cast(from_channel)); i->phys_ensure_find_or_create(cs)->assign(j->ins); - if(!ch[cs].users_insert(*j)) + if(!m_chipChannels[cs].users_insert(*j)) assert(false); - ch[from_channel].users_erase(j); + m_chipChannels[from_channel].users_erase(j); return; } } @@ -2340,24 +1523,24 @@ void MIDIplay::KillOrEvacuate(size_t from_channel, ins );*/ // Kill it - NoteUpdate(j->loc.MidCh, + noteUpdate(j->loc.MidCh, i, Upd_Off, static_cast(from_channel)); } -void MIDIplay::Panic() +void MIDIplay::panic() { - for(uint8_t chan = 0; chan < Ch.size(); chan++) + for(uint8_t chan = 0; chan < m_midiChannels.size(); chan++) { for(uint8_t note = 0; note < 128; note++) realTime_NoteOff(chan, note); } } -void MIDIplay::KillSustainingNotes(int32_t MidCh, int32_t this_adlchn) +void MIDIplay::killSustainingNotes(int32_t midCh, int32_t this_adlchn, uint32_t sustain_type) { - uint32_t first = 0, last = opl.NumChannels; + uint32_t first = 0, last = m_synth.m_numChannels; if(this_adlchn >= 0) { @@ -2365,57 +1548,87 @@ void MIDIplay::KillSustainingNotes(int32_t MidCh, int32_t this_adlchn) last = first + 1; } - for(unsigned c = first; c < last; ++c) + for(uint32_t c = first; c < last; ++c) { - if(ch[c].users_empty()) continue; // Nothing to do + if(m_chipChannels[c].users_empty()) + continue; // Nothing to do - for(AdlChannel::LocationData *jnext = ch[c].users_first; jnext;) + for(AdlChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) { AdlChannel::LocationData *j = jnext; jnext = jnext->next; - if((MidCh < 0 || j->loc.MidCh == MidCh) - && j->sustained) + if((midCh < 0 || j->loc.MidCh == midCh) + && ((j->sustained & sustain_type) != 0)) { int midiins = '?'; if(hooks.onNote) hooks.onNote(hooks.onNote_userData, (int)c, j->loc.note, midiins, 0, 0.0); - ch[c].users_erase(j); + j->sustained &= ~sustain_type; + if(j->sustained == AdlChannel::LocationData::Sustain_None) + m_chipChannels[c].users_erase(j);//Remove only when note is clean from any holders } } // Keyoff the channel, if there are no users left. - if(ch[c].users_empty()) - opl.NoteOff(c); + if(m_chipChannels[c].users_empty()) + m_synth.noteOff(c); } } -void MIDIplay::SetRPN(unsigned MidCh, unsigned value, bool MSB) +void MIDIplay::markSostenutoNotes(int32_t midCh) { - bool nrpn = Ch[MidCh].nrpn; - unsigned addr = Ch[MidCh].lastmrpn * 0x100 + Ch[MidCh].lastlrpn; + uint32_t first = 0, last = m_synth.m_numChannels; + for(uint32_t c = first; c < last; ++c) + { + if(m_chipChannels[c].users_empty()) + continue; // Nothing to do + + for(AdlChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) + { + AdlChannel::LocationData *j = jnext; + jnext = jnext->next; + if((j->loc.MidCh == midCh) && (j->sustained == AdlChannel::LocationData::Sustain_None)) + j->sustained |= AdlChannel::LocationData::Sustain_Sostenuto; + } + } +} + +void MIDIplay::setRPN(size_t midCh, unsigned value, bool MSB) +{ + bool nrpn = m_midiChannels[midCh].nrpn; + unsigned addr = m_midiChannels[midCh].lastmrpn * 0x100 + m_midiChannels[midCh].lastlrpn; switch(addr + nrpn * 0x10000 + MSB * 0x20000) { case 0x0000 + 0*0x10000 + 1*0x20000: // Pitch-bender sensitivity - Ch[MidCh].bendsense_msb = value; - Ch[MidCh].updateBendSensitivity(); + m_midiChannels[midCh].bendsense_msb = value; + m_midiChannels[midCh].updateBendSensitivity(); break; case 0x0000 + 0*0x10000 + 0*0x20000: // Pitch-bender sensitivity LSB - Ch[MidCh].bendsense_lsb = value; - Ch[MidCh].updateBendSensitivity(); + m_midiChannels[midCh].bendsense_lsb = value; + m_midiChannels[midCh].updateBendSensitivity(); break; - case 0x0108 + 1*0x10000 + 1*0x20000: // Vibrato speed - if(value == 64) Ch[MidCh].vibspeed = 1.0; - else if(value < 100) Ch[MidCh].vibspeed = 1.0 / (1.6e-2 * (value ? value : 1)); - else Ch[MidCh].vibspeed = 1.0 / (0.051153846 * value - 3.4965385); - Ch[MidCh].vibspeed *= 2 * 3.141592653 * 5.0; + case 0x0108 + 1*0x10000 + 1*0x20000: + if((m_synthMode & Mode_XG) != 0) // Vibrato speed + { + if(value == 64) m_midiChannels[midCh].vibspeed = 1.0; + else if(value < 100) m_midiChannels[midCh].vibspeed = 1.0 / (1.6e-2 * (value ? value : 1)); + else m_midiChannels[midCh].vibspeed = 1.0 / (0.051153846 * value - 3.4965385); + m_midiChannels[midCh].vibspeed *= 2 * 3.141592653 * 5.0; + } break; - case 0x0109 + 1*0x10000 + 1*0x20000: // Vibrato depth - Ch[MidCh].vibdepth = ((value - 64) * 0.15) * 0.01; + case 0x0109 + 1*0x10000 + 1*0x20000: + if((m_synthMode & Mode_XG) != 0) // Vibrato depth + { + m_midiChannels[midCh].vibdepth = (((int)value - 64) * 0.15) * 0.01; + } break; - case 0x010A + 1*0x10000 + 1*0x20000: // Vibrato delay in millisecons - Ch[MidCh].vibdelay = value ? int64_t(0.2092 * std::exp(0.0795 * (double)value)) : 0; + case 0x010A + 1*0x10000 + 1*0x20000: + if((m_synthMode & Mode_XG) != 0) // Vibrato delay in millisecons + { + m_midiChannels[midCh].vibdelay_us = value ? int64_t(209.2 * std::exp(0.0795 * (double)value)) : 0; + } break; default:/* UI.PrintLn("%s %04X <- %d (%cSB) (ch %u)", "NRPN"+!nrpn, addr, value, "LM"[MSB], MidCh);*/ @@ -2423,67 +1636,53 @@ void MIDIplay::SetRPN(unsigned MidCh, unsigned value, bool MSB) } } -//void MIDIplay::UpdatePortamento(unsigned MidCh) -//{ -// // mt = 2^(portamento/2048) * (1.0 / 5000.0) -// /* -// double mt = std::exp(0.00033845077 * Ch[MidCh].portamento); -// NoteUpdate_All(MidCh, Upd_Pitch); -// */ -// //UI.PrintLn("Portamento %u: %u (unimplemented)", MidCh, Ch[MidCh].portamento); -//} - -void MIDIplay::NoteUpdate_All(uint16_t MidCh, unsigned props_mask) +void MIDIplay::updatePortamento(size_t midCh) { - for(MIDIchannel::activenoteiterator - i = Ch[MidCh].activenotes_begin(); i;) - { - MIDIchannel::activenoteiterator j(i++); - NoteUpdate(MidCh, j, props_mask); - } + double rate = HUGE_VAL; + uint16_t midival = m_midiChannels[midCh].portamento; + if(m_midiChannels[midCh].portamentoEnable && midival > 0) + rate = 350.0 * std::pow(2.0, -0.062 * (1.0 / 128) * midival); + m_midiChannels[midCh].portamentoRate = rate; } -void MIDIplay::NoteOff(uint16_t MidCh, uint8_t note) + +void MIDIplay::noteOff(size_t midCh, uint8_t note) { MIDIchannel::activenoteiterator - i = Ch[MidCh].activenotes_find(note); - + i = m_midiChannels[midCh].activenotes_find(note); if(i) - NoteUpdate(MidCh, i, Upd_Off); + noteUpdate(midCh, i, Upd_Off); } -void MIDIplay::UpdateVibrato(double amount) +void MIDIplay::updateVibrato(double amount) { - for(size_t a = 0, b = Ch.size(); a < b; ++a) + for(size_t a = 0, b = m_midiChannels.size(); a < b; ++a) { - if(Ch[a].hasVibrato() && !Ch[a].activenotes_empty()) + if(m_midiChannels[a].hasVibrato() && !m_midiChannels[a].activenotes_empty()) { - NoteUpdate_All(static_cast(a), Upd_Pitch); - Ch[a].vibpos += amount * Ch[a].vibspeed; + noteUpdateAll(static_cast(a), Upd_Pitch); + m_midiChannels[a].vibpos += amount * m_midiChannels[a].vibspeed; } else - Ch[a].vibpos = 0.0; + m_midiChannels[a].vibpos = 0.0; } } - - - -uint64_t MIDIplay::ChooseDevice(const std::string &name) +size_t MIDIplay::chooseDevice(const std::string &name) { - std::map::iterator i = devices.find(name); + std::map::iterator i = m_midiDevices.find(name); - if(i != devices.end()) + if(i != m_midiDevices.end()) return i->second; - size_t n = devices.size() * 16; - devices.insert(std::make_pair(name, n)); - Ch.resize(n + 16); + size_t n = m_midiDevices.size() * 16; + m_midiDevices.insert(std::make_pair(name, n)); + m_midiChannels.resize(n + 16); return n; } -void MIDIplay::UpdateArpeggio(double) // amount = amount of time passed +void MIDIplay::updateArpeggio(double) // amount = amount of time passed { // If there is an adlib channel that has multiple notes // simulated on the same channel, arpeggio them. @@ -2509,17 +1708,17 @@ void MIDIplay::UpdateArpeggio(double) // amount = amount of time passed ++m_arpeggioCounter; - for(uint32_t c = 0; c < opl.NumChannels; ++c) + for(uint32_t c = 0; c < m_synth.m_numChannels; ++c) { retry_arpeggio: if(c > uint32_t(std::numeric_limits::max())) break; - size_t n_users = ch[c].users_size; + size_t n_users = m_chipChannels[c].users_size; if(n_users > 1) { - AdlChannel::LocationData *i = ch[c].users_first; + AdlChannel::LocationData *i = m_chipChannels[c].users_first; size_t rate_reduction = 3; if(n_users >= 3) @@ -2532,21 +1731,21 @@ retry_arpeggio: n = 0; n < count; ++n) i = i->next; - if(i->sustained == false) + if(i->sustained == AdlChannel::LocationData::Sustain_None) { - if(i->kon_time_until_neglible <= 0l) + if(i->kon_time_until_neglible_us <= 0) { - NoteUpdate( + noteUpdate( i->loc.MidCh, - Ch[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), + m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), Upd_Off, static_cast(c)); goto retry_arpeggio; } - NoteUpdate( + noteUpdate( i->loc.MidCh, - Ch[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), + m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), Upd_Pitch | Upd_Volume | Upd_Pan, static_cast(c)); } @@ -2554,6 +1753,88 @@ retry_arpeggio: } } +void MIDIplay::updateGlide(double amount) +{ + size_t num_channels = m_midiChannels.size(); + + for(size_t channel = 0; channel < num_channels; ++channel) + { + MIDIchannel &midiChan = m_midiChannels[channel]; + if(midiChan.gliding_note_count == 0) + continue; + + for(MIDIchannel::activenoteiterator it = midiChan.activenotes_begin(); + it; ++it) + { + double finalTone = it->noteTone; + double previousTone = it->currentTone; + + bool directionUp = previousTone < finalTone; + double toneIncr = amount * (directionUp ? +it->glideRate : -it->glideRate); + + double currentTone = previousTone + toneIncr; + bool glideFinished = !(directionUp ? (currentTone < finalTone) : (currentTone > finalTone)); + currentTone = glideFinished ? finalTone : currentTone; + + if(currentTone != previousTone) + { + it->currentTone = currentTone; + noteUpdate(static_cast(channel), it, Upd_Pitch); + } + } + } +} + +void MIDIplay::describeChannels(char *str, char *attr, size_t size) +{ + if (!str || size <= 0) + return; + + OPL3 &synth = m_synth; + uint32_t numChannels = synth.m_numChannels; + + uint32_t index = 0; + while(index < numChannels && index < size - 1) + { + const AdlChannel &adlChannel = m_chipChannels[index]; + + AdlChannel::LocationData *loc = adlChannel.users_first; + if(!loc) // off + { + str[index] = '-'; + } + else if(loc->next) // arpeggio + { + str[index] = '@'; + } + else // on + { + switch(synth.m_channelCategory[index]) + { + case OPL3::ChanCat_Regular: + str[index] = '+'; + break; + case OPL3::ChanCat_4op_Master: + case OPL3::ChanCat_4op_Slave: + str[index] = '#'; + break; + default: // rhythm-mode percussion + str[index] = 'r'; + break; + } + } + + uint8_t attribute = 0; + if (loc) // 4-bit color index of MIDI channel + attribute |= (uint8_t)(loc->loc.MidCh & 0xF); + + attr[index] = (char)attribute; + ++index; + } + + str[index] = 0; + attr[index] = 0; +} #ifndef ADLMIDI_DISABLE_CPP_EXTRAS @@ -2569,11 +1850,15 @@ struct AdlInstrumentTester::Impl ADLMIDI_EXPORT AdlInstrumentTester::AdlInstrumentTester(ADL_MIDIPlayer *device) : P(new Impl) { +#ifndef DISABLE_EMBEDDED_BANKS MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); P->cur_gm = 0; P->ins_idx = 0; P->play = play; - P->opl = play ? &play->opl : NULL; + P->opl = play ? &play->m_synth : NULL; +#else + ADL_UNUSED(device); +#endif } ADLMIDI_EXPORT AdlInstrumentTester::~AdlInstrumentTester() @@ -2583,6 +1868,7 @@ ADLMIDI_EXPORT AdlInstrumentTester::~AdlInstrumentTester() ADLMIDI_EXPORT void AdlInstrumentTester::FindAdlList() { +#ifndef DISABLE_EMBEDDED_BANKS const unsigned NumBanks = (unsigned)adl_getBanksCount(); std::set adl_ins_set; for(unsigned bankno = 0; bankno < NumBanks; ++bankno) @@ -2590,32 +1876,39 @@ ADLMIDI_EXPORT void AdlInstrumentTester::FindAdlList() P->adl_ins_list.assign(adl_ins_set.begin(), adl_ins_set.end()); P->ins_idx = 0; NextAdl(0); - P->opl->Silence(); + P->opl->silenceAll(); +#endif } ADLMIDI_EXPORT void AdlInstrumentTester::Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127 { +#ifndef DISABLE_EMBEDDED_BANKS OPL3 *opl = P->opl; if(opl->m_volumeScale == OPL3::VOLUME_NATIVE) - opl->Touch_Real(c, volume * 127 / (127 * 127 * 127) / 2); + opl->touchNote(c, static_cast(volume * 127 / (127 * 127 * 127) / 2)); else { // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) - opl->Touch_Real(c, volume > 8725 ? static_cast(std::log((double)volume) * 11.541561 + (0.5 - 104.22845)) : 0); + opl->touchNote(c, static_cast(volume > 8725 ? static_cast(std::log((double)volume) * 11.541561 + (0.5 - 104.22845)) : 0)); // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) //Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); } +#else + ADL_UNUSED(c); + ADL_UNUSED(volume); +#endif } ADLMIDI_EXPORT void AdlInstrumentTester::DoNote(int note) { +#ifndef DISABLE_EMBEDDED_BANKS MIDIplay *play = P->play; OPL3 *opl = P->opl; if(P->adl_ins_list.empty()) FindAdlList(); const unsigned meta = P->adl_ins_list[P->ins_idx]; - const adlinsdata2 ains(adlins[meta]); + const adlinsdata2 ains = adlinsdata2::from_adldata(::adlins[meta]); int tone = (P->cur_gm & 128) ? (P->cur_gm & 127) : (note + 50); if(ains.tone) @@ -2630,7 +1923,7 @@ ADLMIDI_EXPORT void AdlInstrumentTester::DoNote(int note) } double hertz = 172.00093 * std::exp(0.057762265 * (tone + 0.0)); int32_t adlchannel[2] = { 0, 3 }; - if(ains.adl[0] == ains.adl[1]) + if((ains.flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)) == 0) { adlchannel[1] = -1; adlchannel[0] = 6; // single-op @@ -2649,31 +1942,39 @@ ADLMIDI_EXPORT void AdlInstrumentTester::DoNote(int note) } } - opl->NoteOff(0); - opl->NoteOff(3); - opl->NoteOff(6); + opl->noteOff(0); + opl->noteOff(3); + opl->noteOff(6); for(unsigned c = 0; c < 2; ++c) { if(adlchannel[c] < 0) continue; - opl->Patch((uint16_t)adlchannel[c], ains.adl[c]); - opl->Touch_Real((uint16_t)adlchannel[c], 127 * 127 * 100); - opl->Pan((uint16_t)adlchannel[c], 0x30); - opl->NoteOn((uint16_t)adlchannel[c], hertz); + opl->setPatch(static_cast(adlchannel[c]), ains.adl[c]); + opl->touchNote(static_cast(adlchannel[c]), 63); + opl->setPan(static_cast(adlchannel[c]), 0x30); + opl->noteOn(static_cast(adlchannel[c]), static_cast(adlchannel[1]), hertz); } +#else + ADL_UNUSED(note); +#endif } ADLMIDI_EXPORT void AdlInstrumentTester::NextGM(int offset) { +#ifndef DISABLE_EMBEDDED_BANKS P->cur_gm = (P->cur_gm + 256 + (uint32_t)offset) & 0xFF; FindAdlList(); +#else + ADL_UNUSED(offset); +#endif } ADLMIDI_EXPORT void AdlInstrumentTester::NextAdl(int offset) { +#ifndef DISABLE_EMBEDDED_BANKS //OPL3 *opl = P->opl; if(P->adl_ins_list.empty()) FindAdlList(); const unsigned NumBanks = (unsigned)adl_getBanksCount(); - P->ins_idx = (uint32_t)((int32_t)P->ins_idx + (int32_t)P->adl_ins_list.size() + offset) % P->adl_ins_list.size(); + P->ins_idx = (uint32_t)((int32_t)P->ins_idx + (int32_t)P->adl_ins_list.size() + offset) % (int32_t)P->adl_ins_list.size(); #if 0 UI.Color(15); @@ -2686,10 +1987,10 @@ ADLMIDI_EXPORT void AdlInstrumentTester::NextAdl(int offset) std::fflush(stderr); #endif - for(unsigned a = 0, n = (unsigned)P->adl_ins_list.size(); a < n; ++a) + for(size_t a = 0, n = P->adl_ins_list.size(); a < n; ++a) { const unsigned i = P->adl_ins_list[a]; - const adlinsdata2 ains(adlins[i]); + const adlinsdata2 ains = adlinsdata2::from_adldata(::adlins[i]); char ToneIndication[8] = " "; if(ains.tone) @@ -2704,7 +2005,7 @@ ADLMIDI_EXPORT void AdlInstrumentTester::NextAdl(int offset) } std::printf("%s%s%s%u\t", ToneIndication, - ains.adl[0] != ains.adl[1] ? "[2]" : " ", + (ains.flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)) ? "[2]" : " ", (P->ins_idx == a) ? "->" : "\t", i ); @@ -2715,10 +2016,14 @@ ADLMIDI_EXPORT void AdlInstrumentTester::NextAdl(int offset) std::printf("\n"); } +#else + ADL_UNUSED(offset); +#endif } ADLMIDI_EXPORT bool AdlInstrumentTester::HandleInputChar(char ch) { +#ifndef DISABLE_EMBEDDED_BANKS static const char notes[] = "zsxdcvgbhnjmq2w3er5t6y7ui9o0p"; // c'd'ef'g'a'bC'D'EF'G'A'Bc'd'e switch(ch) @@ -2753,6 +2058,9 @@ ADLMIDI_EXPORT bool AdlInstrumentTester::HandleInputChar(char ch) if(p && *p) DoNote((int)(p - notes) - 12); } +#else + ADL_UNUSED(ch); +#endif return true; } diff --git a/src/sound/adlmidi/adlmidi_opl3.cpp b/src/sound/adlmidi/adlmidi_opl3.cpp index 5d15d002c..f3672d3a2 100644 --- a/src/sound/adlmidi/adlmidi_opl3.cpp +++ b/src/sound/adlmidi/adlmidi_opl3.cpp @@ -22,6 +22,8 @@ */ #include "adlmidi_private.hpp" +#include +#include #ifdef ADLMIDI_HW_OPL static const unsigned OPLBase = 0x388; @@ -42,32 +44,48 @@ static const unsigned OPLBase = 0x388; # endif #endif -#ifdef DISABLE_EMBEDDED_BANKS -/* - Dummy data which replaces adldata.cpp banks database -*/ +static const unsigned adl_emulatorSupport = 0 +#ifndef ADLMIDI_HW_OPL +# ifndef ADLMIDI_DISABLE_NUKED_EMULATOR + | (1u << ADLMIDI_EMU_NUKED) | (1u << ADLMIDI_EMU_NUKED_174) +# endif -const struct adldata adl[] = -{ - {0, 0, (unsigned char)'\0', (unsigned char)'\0', (unsigned char)'\0', 0} -}; +# ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR + | (1u << ADLMIDI_EMU_DOSBOX) +# endif +#endif +; -const struct adlinsdata adlins[] = +//! Check emulator availability +bool adl_isEmulatorAvailable(int emulator) { - {0, 0, 0, 0, 0, 0, 0.0} -}; - -int maxAdlBanks() -{ - return 0; + return (adl_emulatorSupport & (1u << (unsigned)emulator)) != 0; } -const unsigned short banks[][256] = {{0}}; -const char *const banknames[] = {""}; -const AdlBankSetup adlbanksetup[] = {{0, 1, 1, 0, 0}}; -#endif +//! Find highest emulator +int adl_getHighestEmulator() +{ + int emu = -1; + for(unsigned m = adl_emulatorSupport; m > 0; m >>= 1) + ++emu; + return emu; +} -static const unsigned short Operators[23 * 2] = +//! Find lowest emulator +int adl_getLowestEmulator() +{ + int emu = -1; + unsigned m = adl_emulatorSupport; + if(m > 0) + { + for(emu = 0; (m & 1) == 0; m >>= 1) + ++emu; + } + return emu; +} + +//! Per-channel and per-operator registers map +static const uint16_t g_operatorsMap[23 * 2] = { // Channels 0-2 0x000, 0x003, 0x001, 0x004, 0x002, 0x005, // operators 0, 3, 1, 4, 2, 5 @@ -91,7 +109,8 @@ static const unsigned short Operators[23 * 2] = 0x011, 0xFFF }; // operator 13 -static const unsigned short Channels[23] = +//! Channel map to regoster offsets +static const uint16_t g_channelsMap[23] = { 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, // 0..8 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, // 9..17 (secondary set) @@ -129,29 +148,6 @@ static const unsigned short Channels[23] = Ports: ??? */ -void OPL3::setEmbeddedBank(unsigned int bank) -{ - AdlBank = bank; - //Embedded banks are supports 128:128 GM set only - dynamic_banks.clear(); - - if(bank >= static_cast(maxAdlBanks())) - return; - - Bank *bank_pair[2] = - { - &dynamic_banks[0], - &dynamic_banks[PercussionTag] - }; - - for(unsigned i = 0; i < 256; ++i) - { - size_t meta = banks[bank][i]; - adlinsdata2 &ins = bank_pair[i / 128]->ins[i % 128]; - ins = adlinsdata2(adlins[meta]); - } -} - static adlinsdata2 makeEmptyInstrument() { adlinsdata2 ins; @@ -160,126 +156,239 @@ static adlinsdata2 makeEmptyInstrument() return ins; } -const adlinsdata2 OPL3::emptyInstrument = makeEmptyInstrument(); +const adlinsdata2 OPL3::m_emptyInstrument = makeEmptyInstrument(); OPL3::OPL3() : - NumCards(1), - NumFourOps(0), - HighTremoloMode(false), - HighVibratoMode(false), - AdlPercussionMode(false), + m_numChips(1), + m_numFourOps(0), + m_deepTremoloMode(false), + m_deepVibratoMode(false), + m_rhythmMode(false), + m_softPanning(false), m_musicMode(MODE_MIDI), m_volumeScale(VOLUME_Generic) { + m_insBankSetup.volumeModel = OPL3::VOLUME_Generic; + m_insBankSetup.deepTremolo = false; + m_insBankSetup.deepVibrato = false; + m_insBankSetup.adLibPercussions = false; + m_insBankSetup.scaleModulators = false; + #ifdef DISABLE_EMBEDDED_BANKS - AdlBank = ~0u; + m_embeddedBank = CustomBankTag; #else setEmbeddedBank(0); #endif } -void OPL3::Poke(size_t card, uint16_t index, uint8_t value) +bool OPL3::setupLocked() { - #ifdef ADLMIDI_HW_OPL - (void)card; - unsigned o = index >> 8; + return (m_musicMode == MODE_CMF || + m_musicMode == MODE_IMF || + m_musicMode == MODE_RSXX); +} + +void OPL3::setEmbeddedBank(uint32_t bank) +{ +#ifndef DISABLE_EMBEDDED_BANKS + m_embeddedBank = bank; + //Embedded banks are supports 128:128 GM set only + m_insBanks.clear(); + + if(bank >= static_cast(maxAdlBanks())) + return; + + Bank *bank_pair[2] = + { + &m_insBanks[0], + &m_insBanks[PercussionTag] + }; + + for(unsigned i = 0; i < 256; ++i) + { + size_t meta = banks[bank][i]; + adlinsdata2 &ins = bank_pair[i / 128]->ins[i % 128]; + ins = adlinsdata2::from_adldata(::adlins[meta]); + } +#else + ADL_UNUSED(bank); +#endif +} + +void OPL3::writeReg(size_t chip, uint16_t address, uint8_t value) +{ +#ifdef ADLMIDI_HW_OPL + ADL_UNUSED(chip); + unsigned o = address >> 8; unsigned port = OPLBase + o * 2; #ifdef __DJGPP__ - outportb(port, index); + outportb(port, address); for(unsigned c = 0; c < 6; ++c) inportb(port); outportb(port + 1, value); for(unsigned c = 0; c < 35; ++c) inportb(port); #endif #ifdef __WATCOMC__ - outp(port, index); + outp(port, address); for(uint16_t c = 0; c < 6; ++c) inp(port); outp(port + 1, value); for(uint16_t c = 0; c < 35; ++c) inp(port); #endif//__WATCOMC__ - #else - cardsOP2[card]->writeReg(index, value); - #endif +#else//ADLMIDI_HW_OPL + m_chips[chip]->writeReg(address, value); +#endif +} + +void OPL3::writeRegI(size_t chip, uint32_t address, uint32_t value) +{ +#ifdef ADLMIDI_HW_OPL + writeReg(chip, static_cast(address), static_cast(value)); +#else//ADLMIDI_HW_OPL + m_chips[chip]->writeReg(static_cast(address), static_cast(value)); +#endif +} + +void OPL3::writePan(size_t chip, uint32_t address, uint32_t value) +{ +#ifndef ADLMIDI_HW_OPL + m_chips[chip]->writePan(static_cast(address), static_cast(value)); +#else + ADL_UNUSED(chip); + ADL_UNUSED(address); + ADL_UNUSED(value); +#endif } -void OPL3::NoteOff(size_t c) +void OPL3::noteOff(size_t c) { - size_t card = c / 23, cc = c % 23; + size_t chip = c / 23, cc = c % 23; if(cc >= 18) { - regBD[card] &= ~(0x10 >> (cc - 18)); - Poke(card, 0xBD, regBD[card]); + m_regBD[chip] &= ~(0x10 >> (cc - 18)); + writeRegI(chip, 0xBD, m_regBD[chip]); return; } - Poke(card, 0xB0 + Channels[cc], pit[c] & 0xDF); + writeRegI(chip, 0xB0 + g_channelsMap[cc], m_keyBlockFNumCache[c] & 0xDF); } -void OPL3::NoteOn(unsigned c, double hertz) // Hertz range: 0..131071 +void OPL3::noteOn(size_t c1, size_t c2, double hertz) // Hertz range: 0..131071 { - unsigned card = c / 23, cc = c % 23; - unsigned x = 0x2000; + size_t chip = c1 / 23, cc1 = c1 % 23, cc2 = c2 % 23; + uint32_t octave = 0, ftone = 0, mul_offset = 0; - if(hertz < 0 || hertz > 131071) // Avoid infinite loop + if(hertz < 0) return; - while(hertz >= 1023.5) + //Basic range until max of octaves reaching + while((hertz >= 1023.5) && (octave < 0x1C00)) { hertz /= 2.0; // Calculate octave - x += 0x400; + octave += 0x400; + } + //Extended range, rely on frequency multiplication increment + while(hertz >= 1022.75) + { + hertz /= 2.0; // Calculate octave + mul_offset++; } - x += static_cast(hertz + 0.5); - unsigned chn = Channels[cc]; + ftone = octave + static_cast(hertz + 0.5); + uint32_t chn = g_channelsMap[cc1]; + const adldata &patch1 = m_insCache[c1]; + const adldata &patch2 = m_insCache[c2 < m_insCache.size() ? c2 : 0]; - if(cc >= 18) + if(cc1 < 18) { - regBD[card] |= (0x10 >> (cc - 18)); - Poke(card, 0x0BD, regBD[card]); - x &= ~0x2000u; - //x |= 0x800; // for test + ftone += 0x2000u; /* Key-ON [KON] */ + + const bool natural_4op = (m_channelCategory[c1] == ChanCat_4op_Master); + const size_t opsCount = natural_4op ? 4 : 2; + const uint16_t op_addr[4] = + { + g_operatorsMap[cc1 * 2 + 0], g_operatorsMap[cc1 * 2 + 1], + g_operatorsMap[cc2 * 2 + 0], g_operatorsMap[cc2 * 2 + 1] + }; + const uint32_t ops[4] = + { + patch1.modulator_E862 & 0xFF, + patch1.carrier_E862 & 0xFF, + patch2.modulator_E862 & 0xFF, + patch2.carrier_E862 & 0xFF + }; + + for(size_t op = 0; op < opsCount; op++) + { + if((op > 0) && (op_addr[op] == 0xFFF)) + break; + if(mul_offset > 0) + { + uint32_t dt = ops[op] & 0xF0; + uint32_t mul = ops[op] & 0x0F; + if((mul + mul_offset) > 0x0F) + { + mul_offset = 0; + mul = 0x0F; + } + writeRegI(chip, 0x20 + op_addr[op], (dt | (mul + mul_offset)) & 0xFF); + } + else + { + writeRegI(chip, 0x20 + op_addr[op], ops[op] & 0xFF); + } + } } if(chn != 0xFFF) { - Poke(card, 0xA0 + chn, x & 0xFF); - Poke(card, 0xB0 + chn, pit[c] = static_cast(x >> 8)); + writeRegI(chip , 0xA0 + chn, (ftone & 0xFF)); + writeRegI(chip , 0xB0 + chn, (ftone >> 8)); + m_keyBlockFNumCache[c1] = (ftone >> 8); + } + + if(cc1 >= 18) + { + m_regBD[chip ] |= (0x10 >> (cc1 - 18)); + writeRegI(chip , 0x0BD, m_regBD[chip ]); + //x |= 0x800; // for test } } -void OPL3::Touch_Real(unsigned c, unsigned volume, uint8_t brightness) +void OPL3::touchNote(size_t c, uint8_t volume, uint8_t brightness) { if(volume > 63) volume = 63; - size_t card = c / 23, cc = c % 23; - const adldata &adli = ins[c]; - uint16_t o1 = Operators[cc * 2 + 0]; - uint16_t o2 = Operators[cc * 2 + 1]; + size_t chip = c / 23, cc = c % 23; + const adldata &adli = m_insCache[c]; + uint16_t o1 = g_operatorsMap[cc * 2 + 0]; + uint16_t o2 = g_operatorsMap[cc * 2 + 1]; uint8_t x = adli.modulator_40, y = adli.carrier_40; - uint16_t mode = 1; // 2-op AM + uint32_t mode = 1; // 2-op AM - if(four_op_category[c] == 0 || four_op_category[c] == 3) + if(m_channelCategory[c] == ChanCat_Regular || + m_channelCategory[c] == ChanCat_Rhythm_Bass) { mode = adli.feedconn & 1; // 2-op FM or 2-op AM } - else if(four_op_category[c] == 1 || four_op_category[c] == 2) + else if(m_channelCategory[c] == ChanCat_4op_Master || + m_channelCategory[c] == ChanCat_4op_Slave) { const adldata *i0, *i1; - if(four_op_category[c] == 1) + if(m_channelCategory[c] == ChanCat_4op_Master) { i0 = &adli; - i1 = &ins[c + 3]; + i1 = &m_insCache[c + 3]; mode = 2; // 4-op xx-xx ops 1&2 } else { - i0 = &ins[c - 3]; + i0 = &m_insCache[c - 3]; i1 = &adli; mode = 6; // 4-op xx-xx ops 3&4 } @@ -303,14 +412,14 @@ void OPL3::Touch_Real(unsigned c, unsigned volume, uint8_t brightness) if(m_musicMode == MODE_RSXX) { - Poke(card, 0x40 + o1, x); + writeRegI(chip, 0x40 + o1, x); if(o2 != 0xFFF) - Poke(card, 0x40 + o2, y - volume / 2); + writeRegI(chip, 0x40 + o2, y - volume / 2); } else { - bool do_modulator = do_ops[ mode ][ 0 ] || ScaleModulators; - bool do_carrier = do_ops[ mode ][ 1 ] || ScaleModulators; + bool do_modulator = do_ops[ mode ][ 0 ] || m_scaleModulators; + bool do_carrier = do_ops[ mode ][ 1 ] || m_scaleModulators; uint32_t modulator = do_modulator ? (x | 63) - volume + volume * (x & 63) / 63 : x; uint32_t carrier = do_carrier ? (y | 63) - volume + volume * (y & 63) / 63 : y; @@ -324,9 +433,9 @@ void OPL3::Touch_Real(unsigned c, unsigned volume, uint8_t brightness) carrier = (carrier | 63) - brightness + brightness * (carrier & 63) / 63; } - Poke(card, 0x40 + o1, modulator); + writeRegI(chip, 0x40 + o1, modulator); if(o2 != 0xFFF) - Poke(card, 0x40 + o2, carrier); + writeRegI(chip, 0x40 + o2, carrier); } // Correct formula (ST3, AdPlug): @@ -351,70 +460,99 @@ void OPL3::Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127 } }*/ -void OPL3::Patch(uint16_t c, const adldata &adli) +void OPL3::setPatch(size_t c, const adldata &instrument) { - uint16_t card = c / 23, cc = c % 23; + size_t chip = c / 23, cc = c % 23; static const uint8_t data[4] = {0x20, 0x60, 0x80, 0xE0}; - ins[c] = adli; - uint16_t o1 = Operators[cc * 2 + 0]; - uint16_t o2 = Operators[cc * 2 + 1]; - unsigned x = adli.modulator_E862, y = adli.carrier_E862; + m_insCache[c] = instrument; + uint16_t o1 = g_operatorsMap[cc * 2 + 0]; + uint16_t o2 = g_operatorsMap[cc * 2 + 1]; + unsigned x = instrument.modulator_E862, y = instrument.carrier_E862; - for(unsigned a = 0; a < 4; ++a, x >>= 8, y >>= 8) + for(size_t a = 0; a < 4; ++a, x >>= 8, y >>= 8) { - Poke(card, data[a] + o1, x & 0xFF); + writeRegI(chip, data[a] + o1, x & 0xFF); if(o2 != 0xFFF) - Poke(card, data[a] + o2, y & 0xFF); + writeRegI(chip, data[a] + o2, y & 0xFF); } } -void OPL3::Pan(unsigned c, unsigned value) +void OPL3::setPan(size_t c, uint8_t value) { - unsigned card = c / 23, cc = c % 23; - - if(Channels[cc] != 0xFFF) - Poke(card, 0xC0 + Channels[cc], ins[c].feedconn | value); -} - -void OPL3::Silence() // Silence all OPL channels. -{ - for(unsigned c = 0; c < NumChannels; ++c) + size_t chip = c / 23, cc = c % 23; + if(g_channelsMap[cc] != 0xFFF) { - NoteOff(c); - Touch_Real(c, 0); - } -} - -void OPL3::updateFlags() -{ - unsigned fours = NumFourOps; - - for(unsigned card = 0; card < NumCards; ++card) - { - Poke(card, 0x0BD, regBD[card] = (HighTremoloMode * 0x80 - + HighVibratoMode * 0x40 - + AdlPercussionMode * 0x20)); - unsigned fours_this_card = std::min(fours, 6u); - Poke(card, 0x104, (1 << fours_this_card) - 1); - fours -= fours_this_card; - } - - // Mark all channels that are reserved for four-operator function - if(AdlPercussionMode == 1) - for(unsigned a = 0; a < NumCards; ++a) +#ifndef ADLMIDI_HW_OPL + if (m_softPanning) { - for(unsigned b = 0; b < 5; ++b) - four_op_category[a * 23 + 18 + b] = static_cast(b + 3); - for(unsigned b = 0; b < 3; ++b) - four_op_category[a * 23 + 6 + b] = 8; + writePan(chip, g_channelsMap[cc], value); + writeRegI(chip, 0xC0 + g_channelsMap[cc], m_insCache[c].feedconn | OPL_PANNING_BOTH); } + else + { +#endif + int panning = 0; + if(value < 64 + 32) panning |= OPL_PANNING_LEFT; + if(value >= 64 - 32) panning |= OPL_PANNING_RIGHT; + writePan(chip, g_channelsMap[cc], 64); + writeRegI(chip, 0xC0 + g_channelsMap[cc], m_insCache[c].feedconn | panning); +#ifndef ADLMIDI_HW_OPL + } +#endif + } +} - unsigned nextfour = 0; - - for(unsigned a = 0; a < NumFourOps; ++a) +void OPL3::silenceAll() // Silence all OPL channels. +{ + for(size_t c = 0; c < m_numChannels; ++c) { - four_op_category[nextfour ] = 1; - four_op_category[nextfour + 3] = 2; + noteOff(c); + touchNote(c, 0); + } +} + +void OPL3::updateChannelCategories() +{ + const uint32_t fours = m_numFourOps; + + for(uint32_t chip = 0, fours_left = fours; chip < m_numChips; ++chip) + { + m_regBD[chip] = (m_deepTremoloMode * 0x80 + m_deepVibratoMode * 0x40 + m_rhythmMode * 0x20); + writeRegI(chip, 0x0BD, m_regBD[chip]); + uint32_t fours_this_chip = std::min(fours_left, static_cast(6u)); + writeRegI(chip, 0x104, (1 << fours_this_chip) - 1); + fours_left -= fours_this_chip; + } + + if(!m_rhythmMode) + { + for(size_t a = 0, n = m_numChips; a < n; ++a) + { + for(size_t b = 0; b < 23; ++b) + { + m_channelCategory[a * 23 + b] = + (b >= 18) ? ChanCat_Rhythm_Slave : ChanCat_Regular; + } + } + } + else + { + for(size_t a = 0, n = m_numChips; a < n; ++a) + { + for(size_t b = 0; b < 23; ++b) + { + m_channelCategory[a * 23 + b] = + (b >= 18) ? static_cast(ChanCat_Rhythm_Bass + (b - 18)) : + (b >= 6 && b < 9) ? ChanCat_Rhythm_Slave : ChanCat_Regular; + } + } + } + + uint32_t nextfour = 0; + for(uint32_t a = 0; a < fours; ++a) + { + m_channelCategory[nextfour] = ChanCat_4op_Master; + m_channelCategory[nextfour + 3] = ChanCat_4op_Slave; switch(a % 6) { @@ -434,19 +572,45 @@ void OPL3::updateFlags() break; } } + +/**/ +/* + In two-op mode, channels 0..8 go as follows: + Op1[port] Op2[port] + Channel 0: 00 00 03 03 + Channel 1: 01 01 04 04 + Channel 2: 02 02 05 05 + Channel 3: 06 08 09 0B + Channel 4: 07 09 10 0C + Channel 5: 08 0A 11 0D + Channel 6: 12 10 15 13 + Channel 7: 13 11 16 14 + Channel 8: 14 12 17 15 + In four-op mode, channels 0..8 go as follows: + Op1[port] Op2[port] Op3[port] Op4[port] + Channel 0: 00 00 03 03 06 08 09 0B + Channel 1: 01 01 04 04 07 09 10 0C + Channel 2: 02 02 05 05 08 0A 11 0D + Channel 3: CHANNEL 0 SLAVE + Channel 4: CHANNEL 1 SLAVE + Channel 5: CHANNEL 2 SLAVE + Channel 6: 12 10 15 13 + Channel 7: 13 11 16 14 + Channel 8: 14 12 17 15 + Same goes principally for channels 9-17 respectively. + */ } -void OPL3::updateDeepFlags() +void OPL3::commitDeepFlags() { - for(unsigned card = 0; card < NumCards; ++card) + for(size_t chip = 0; chip < m_numChips; ++chip) { - Poke(card, 0x0BD, regBD[card] = (HighTremoloMode * 0x80 - + HighVibratoMode * 0x40 - + AdlPercussionMode * 0x20)); + m_regBD[chip] = (m_deepTremoloMode * 0x80 + m_deepVibratoMode * 0x40 + m_rhythmMode * 0x20); + writeRegI(chip, 0x0BD, m_regBD[chip]); } } -void OPL3::ChangeVolumeRangesModel(ADLMIDI_VolumeModels volumeModel) +void OPL3::setVolumeScaleModel(ADLMIDI_VolumeModels volumeModel) { switch(volumeModel) { @@ -475,19 +639,37 @@ void OPL3::ChangeVolumeRangesModel(ADLMIDI_VolumeModels volumeModel) } } -#ifndef ADLMIDI_HW_OPL -void OPL3::ClearChips() +ADLMIDI_VolumeModels OPL3::getVolumeScaleModel() { - for(size_t i = 0; i < cardsOP2.size(); i++) - cardsOP2[i].reset(NULL); - cardsOP2.clear(); + switch(m_volumeScale) + { + default: + case OPL3::VOLUME_Generic: + return ADLMIDI_VolumeModel_Generic; + case OPL3::VOLUME_NATIVE: + return ADLMIDI_VolumeModel_NativeOPL3; + case OPL3::VOLUME_DMX: + return ADLMIDI_VolumeModel_DMX; + case OPL3::VOLUME_APOGEE: + return ADLMIDI_VolumeModel_APOGEE; + case OPL3::VOLUME_9X: + return ADLMIDI_VolumeModel_9X; + } +} + +#ifndef ADLMIDI_HW_OPL +void OPL3::clearChips() +{ + for(size_t i = 0; i < m_chips.size(); i++) + m_chips[i].reset(NULL); + m_chips.clear(); } #endif -void OPL3::Reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) +void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) { #ifndef ADLMIDI_HW_OPL - ClearChips(); + clearChips(); #else (void)emulator; (void)PCM_RATE; @@ -495,24 +677,27 @@ void OPL3::Reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) #if !defined(ADLMIDI_AUDIO_TICK_HANDLER) (void)audioTickHandler; #endif - ins.clear(); - pit.clear(); - regBD.clear(); + m_insCache.clear(); + m_keyBlockFNumCache.clear(); + m_regBD.clear(); #ifndef ADLMIDI_HW_OPL - cardsOP2.resize(NumCards, AdlMIDI_SPtr()); + m_chips.resize(m_numChips, AdlMIDI_SPtr()); #endif - NumChannels = NumCards * 23; - ins.resize(NumChannels, adl[adlDefaultNumber]); - pit.resize(NumChannels, 0); - regBD.resize(NumCards, 0); - four_op_category.resize(NumChannels, 0); + const struct adldata defaultInsCache = { 0x1557403,0x005B381, 0x49,0x80, 0x4, +0 }; + m_numChannels = m_numChips * 23; + m_insCache.resize(m_numChannels, defaultInsCache); + m_keyBlockFNumCache.resize(m_numChannels, 0); + m_regBD.resize(m_numChips, 0); + m_channelCategory.resize(m_numChannels, 0); - for(unsigned p = 0, a = 0; a < NumCards; ++a) + for(size_t p = 0, a = 0; a < m_numChips; ++a) { - for(unsigned b = 0; b < 18; ++b) four_op_category[p++] = 0; - for(unsigned b = 0; b < 5; ++b) four_op_category[p++] = 8; + for(size_t b = 0; b < 18; ++b) + m_channelCategory[p++] = 0; + for(size_t b = 0; b < 5; ++b) + m_channelCategory[p++] = ChanCat_Rhythm_Slave; } static const uint16_t data[] = @@ -521,15 +706,17 @@ void OPL3::Reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) 0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable 0x001, 32, 0x105, 1 // Enable wave, OPL3 extensions }; - unsigned fours = NumFourOps; +// size_t fours = m_numFourOps; - for(size_t i = 0; i < NumCards; ++i) + for(size_t i = 0; i < m_numChips; ++i) { #ifndef ADLMIDI_HW_OPL OPLChipBase *chip; switch(emulator) { default: + assert(false); + abort(); #ifndef ADLMIDI_DISABLE_NUKED_EMULATOR case ADLMIDI_EMU_NUKED: /* Latest Nuked OPL3 */ chip = new NukedOPL3; @@ -544,91 +731,23 @@ void OPL3::Reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) break; #endif } - cardsOP2[i].reset(chip); + m_chips[i].reset(chip); chip->setChipId((uint32_t)i); chip->setRate((uint32_t)PCM_RATE); - if(runAtPcmRate) + if(m_runAtPcmRate) chip->setRunningAtPcmRate(true); # if defined(ADLMIDI_AUDIO_TICK_HANDLER) chip->setAudioTickHandlerInstance(audioTickHandler); # endif #endif // ADLMIDI_HW_OPL - for(unsigned a = 0; a < 18; ++a) Poke(i, 0xB0 + Channels[a], 0x00); - for(unsigned a = 0; a < sizeof(data) / sizeof(*data); a += 2) - Poke(i, data[a], static_cast(data[a + 1])); - Poke(i, 0x0BD, regBD[i] = (HighTremoloMode * 0x80 - + HighVibratoMode * 0x40 - + AdlPercussionMode * 0x20)); - unsigned fours_this_card = std::min(fours, 6u); - Poke(i, 0x104, (1 << fours_this_card) - 1); - //fprintf(stderr, "Card %u: %u four-ops.\n", card, fours_this_card); - fours -= fours_this_card; + /* Clean-up channels from any playing junk sounds */ + for(size_t a = 0; a < 18; ++a) + writeRegI(i, 0xB0 + g_channelsMap[a], 0x00); + for(size_t a = 0; a < sizeof(data) / sizeof(*data); a += 2) + writeRegI(i, data[a], (data[a + 1])); } - // Mark all channels that are reserved for four-operator function - if(AdlPercussionMode == 1) - { - for(unsigned a = 0; a < NumCards; ++a) - { - for(unsigned b = 0; b < 5; ++b) four_op_category[a * 23 + 18 + b] = static_cast(b + 3); - for(unsigned b = 0; b < 3; ++b) four_op_category[a * 23 + 6 + b] = 8; - } - } - unsigned nextfour = 0; - - for(unsigned a = 0; a < NumFourOps; ++a) - { - four_op_category[nextfour ] = 1; - four_op_category[nextfour + 3] = 2; - - switch(a % 6) - { - case 0: - case 1: - nextfour += 1; - break; - - case 2: - nextfour += 9 - 2; - break; - - case 3: - case 4: - nextfour += 1; - break; - - case 5: - nextfour += 23 - 9 - 2; - break; - } - } - - /**/ - /* - In two-op mode, channels 0..8 go as follows: - Op1[port] Op2[port] - Channel 0: 00 00 03 03 - Channel 1: 01 01 04 04 - Channel 2: 02 02 05 05 - Channel 3: 06 08 09 0B - Channel 4: 07 09 10 0C - Channel 5: 08 0A 11 0D - Channel 6: 12 10 15 13 - Channel 7: 13 11 16 14 - Channel 8: 14 12 17 15 - In four-op mode, channels 0..8 go as follows: - Op1[port] Op2[port] Op3[port] Op4[port] - Channel 0: 00 00 03 03 06 08 09 0B - Channel 1: 01 01 04 04 07 09 10 0C - Channel 2: 02 02 05 05 08 0A 11 0D - Channel 3: CHANNEL 0 SLAVE - Channel 4: CHANNEL 1 SLAVE - Channel 5: CHANNEL 2 SLAVE - Channel 6: 12 10 15 13 - Channel 7: 13 11 16 14 - Channel 8: 14 12 17 15 - Same goes principally for channels 9-17 respectively. - */ - Silence(); + updateChannelCategories(); + silenceAll(); } diff --git a/src/sound/adlmidi/adlmidi_private.cpp b/src/sound/adlmidi/adlmidi_private.cpp index 1ee7c4a33..4e8e488af 100644 --- a/src/sound/adlmidi/adlmidi_private.cpp +++ b/src/sound/adlmidi/adlmidi_private.cpp @@ -27,53 +27,58 @@ std::string ADLMIDI_ErrorString; // Generator callback on audio rate ticks +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate) { reinterpret_cast(instance)->AudioTick(chipId, rate); } +#endif -int adlRefreshNumCards(ADL_MIDIPlayer *device) +int adlCalculateFourOpChannels(MIDIplay *play, bool silent) { - unsigned n_fourop[2] = {0, 0}, n_total[2] = {0, 0}; - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + size_t n_fourop[2] = {0, 0}, n_total[2] = {0, 0}; //Automatically calculate how much 4-operator channels is necessary - if(play->opl.AdlBank == ~0u) +#ifndef DISABLE_EMBEDDED_BANKS + if(play->m_synth.m_embeddedBank == OPL3::CustomBankTag) +#endif { //For custom bank - OPL3::BankMap::iterator it = play->opl.dynamic_banks.begin(); - OPL3::BankMap::iterator end = play->opl.dynamic_banks.end(); + OPL3::BankMap::iterator it = play->m_synth.m_insBanks.begin(); + OPL3::BankMap::iterator end = play->m_synth.m_insBanks.end(); for(; it != end; ++it) { - uint16_t bank = it->first; - unsigned div = (bank & OPL3::PercussionTag) ? 1 : 0; - for(unsigned i = 0; i < 128; ++i) + size_t bank = it->first; + size_t div = (bank & OPL3::PercussionTag) ? 1 : 0; + for(size_t i = 0; i < 128; ++i) { adlinsdata2 &ins = it->second.ins[i]; if(ins.flags & adlinsdata::Flag_NoSound) continue; - if((ins.adl[0] != ins.adl[1]) && ((ins.flags & adlinsdata::Flag_Pseudo4op) == 0)) + if((ins.flags & adlinsdata::Flag_Real4op) != 0) ++n_fourop[div]; ++n_total[div]; } } } +#ifndef DISABLE_EMBEDDED_BANKS else { //For embedded bank - for(unsigned a = 0; a < 256; ++a) + for(size_t a = 0; a < 256; ++a) { - unsigned insno = banks[play->m_setup.AdlBank][a]; + size_t insno = banks[play->m_setup.bankId][a]; if(insno == 198) continue; ++n_total[a / 128]; - adlinsdata2 ins(adlins[insno]); - if(ins.flags & adlinsdata::Flag_Real4op) + adlinsdata2 ins = adlinsdata2::from_adldata(::adlins[insno]); + if((ins.flags & adlinsdata::Flag_Real4op) != 0) ++n_fourop[a / 128]; } } +#endif - unsigned numFourOps = 0; + size_t numFourOps = 0; // All 2ops (no 4ops) if((n_fourop[0] == 0) && (n_fourop[1] == 0)) @@ -94,7 +99,10 @@ int adlRefreshNumCards(ADL_MIDIPlayer *device) : (play->m_setup.NumCards == 1 ? 1 : play->m_setup.NumCards * 4); */ - play->opl.NumFourOps = play->m_setup.NumFourOps = (numFourOps * play->m_setup.NumCards); + play->m_synth.m_numFourOps = static_cast(numFourOps * play->m_synth.m_numChips); + // Update channel categories and set up four-operator channels + if(!silent) + play->m_synth.updateChannelCategories(); return 0; } diff --git a/src/sound/adlmidi/adlmidi_private.hpp b/src/sound/adlmidi/adlmidi_private.hpp index 0e63b5a61..59ba555d9 100644 --- a/src/sound/adlmidi/adlmidi_private.hpp +++ b/src/sound/adlmidi/adlmidi_private.hpp @@ -28,18 +28,16 @@ #ifndef ADLMIDI_EXPORT # if defined (_WIN32) && defined(ADLMIDI_BUILD_DLL) # define ADLMIDI_EXPORT __declspec(dllexport) -# elif defined (LIBADLMIDI_VISIBILITY) +# elif defined (LIBADLMIDI_VISIBILITY) && defined (__GNUC__) # define ADLMIDI_EXPORT __attribute__((visibility ("default"))) # else # define ADLMIDI_EXPORT # endif #endif -// Require declarations of unstable API for extern "C" -#define ADLMIDI_UNSTABLE_API #ifdef _WIN32 -#define NOMINMAX +#define NOMINMAX 1 #endif #if defined(_WIN32) && !defined(__WATCOMC__) @@ -51,7 +49,7 @@ typedef __int64 ssize_t; # else typedef __int32 ssize_t; # endif -# define NOMINMAX //Don't override std::min and std::max +# define NOMINMAX 1 //Don't override std::min and std::max # else # ifdef _WIN64 typedef int64_t ssize_t; @@ -84,6 +82,7 @@ typedef int32_t ssize_t; //#else #include #include +#include // nothrow //#endif #include #include @@ -131,16 +130,28 @@ typedef int32_t ssize_t; #define INT32_MAX 0x7fffffff #endif -#include "fraction.hpp" +#include "file_reader.hpp" + +#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER +// Rename class to avoid ABI collisions +#define BW_MidiSequencer AdlMidiSequencer +#include "midi_sequencer.hpp" +typedef BW_MidiSequencer MidiSequencer; +#endif//ADLMIDI_DISABLE_MIDI_SEQUENCER + #ifndef ADLMIDI_HW_OPL #include "chips/opl_chip_base.h" #endif #include "adldata.hh" + +#define ADLMIDI_BUILD #include "adlmidi.h" //Main API + #ifndef ADLMIDI_DISABLE_CPP_EXTRAS #include "adlmidi.hpp" //Extra C++ API #endif + #include "adlmidi_ptr.hpp" #include "adlmidi_bankmap.h" @@ -150,6 +161,14 @@ typedef int32_t ssize_t; #define OPL_PANNING_RIGHT 0x20 #define OPL_PANNING_BOTH 0x30 +#ifdef ADLMIDI_HW_OPL +#define ADL_MAX_CHIPS 1 +#define ADL_MAX_CHIPS_STR "1" //Why not just "#MaxCards" ? Watcom fails to pass this with "syntax error" :-P +#else +#define ADL_MAX_CHIPS 100 +#define ADL_MAX_CHIPS_STR "100" +#endif + extern std::string ADLMIDI_ErrorString; /* @@ -158,7 +177,7 @@ extern std::string ADLMIDI_ErrorString; template inline Real adl_cvtReal(int32_t x) { - return x * ((Real)1 / INT16_MAX); + return static_cast(x) * (static_cast(1) / static_cast(INT16_MAX)); } inline int32_t adl_cvtS16(int32_t x) @@ -199,104 +218,271 @@ inline int32_t adl_cvtU32(int32_t x) return (uint32_t)adl_cvtS32(x) - (uint32_t)INT32_MIN; } -class MIDIplay; struct ADL_MIDIPlayer; +class MIDIplay; +/** + * @brief OPL3 Chip management class + */ class OPL3 { -public: friend class MIDIplay; friend class AdlInstrumentTester; - uint32_t NumChannels; - char ____padding[4]; - ADL_MIDIPlayer *_parent; -#ifndef ADLMIDI_HW_OPL - std::vector > cardsOP2; -#endif -private: - std::vector ins; // patch data, cached, needed by Touch() - std::vector pit; // value poked to B0, cached, needed by NoteOff)( - std::vector regBD; - - friend int adlRefreshNumCards(ADL_MIDIPlayer *device); + friend int adlCalculateFourOpChannels(MIDIplay *play, bool silent); public: + enum + { + PercussionTag = 1 << 15, + CustomBankTag = 0xFFFFFFFF + }; + + //! Total number of chip channels between all running emulators + uint32_t m_numChannels; + //! Just a padding. Reserved. + char _padding[4]; +#ifndef ADLMIDI_HW_OPL + //! Running chip emulators + std::vector > m_chips; +#endif + +private: + //! Cached patch data, needed by Touch() + std::vector m_insCache; + //! Value written to B0, cached, needed by NoteOff. + /*! Contains Key on/off state, octave block and frequency number values + */ + std::vector m_keyBlockFNumCache; + //! Cached BD registry value (flags register: DeepTremolo, DeepVibrato, and RhythmMode) + std::vector m_regBD; + +public: + /** + * @brief MIDI bank entry + */ struct Bank { + //! MIDI Bank instruments adlinsdata2 ins[128]; }; typedef BasicBankMap BankMap; - BankMap dynamic_banks; - AdlBankSetup dynamic_bank_setup; -public: - void setEmbeddedBank(unsigned int bank); - static const adlinsdata2 emptyInstrument; - enum { PercussionTag = 1 << 15 }; + //! MIDI bank instruments data + BankMap m_insBanks; + //! MIDI bank-wide setup + AdlBankSetup m_insBankSetup; +public: + //! Blank instrument template + static const adlinsdata2 m_emptyInstrument; //! Total number of running concurrent emulated chips - unsigned int NumCards; - //! Currently running embedded bank number. "~0" means usign of the custom bank. - unsigned int AdlBank; + uint32_t m_numChips; + //! Currently running embedded bank number. "CustomBankTag" means usign of the custom bank. + uint32_t m_embeddedBank; //! Total number of needed four-operator channels in all running chips - unsigned int NumFourOps; + uint32_t m_numFourOps; //! Turn global Deep Tremolo mode on - bool HighTremoloMode; + bool m_deepTremoloMode; //! Turn global Deep Vibrato mode on - bool HighVibratoMode; - //! Use AdLib percussion mode - bool AdlPercussionMode; + bool m_deepVibratoMode; + //! Use Rhythm Mode percussions + bool m_rhythmMode; //! Carriers-only are scaled by default by volume level. This flag will tell to scale modulators too. - bool ScaleModulators; + bool m_scaleModulators; //! Run emulator at PCM rate if that possible. Reduces sounding accuracy, but decreases CPU usage on lower rates. - bool runAtPcmRate; - // ! Required to play CMF files. Can be turned on by using of "CMF" volume model - //bool LogarithmicVolumes; //[REPLACED WITH "m_volumeScale == VOLUME_NATIVE", DEPRECATED!!!] - // ! Required to play EA-MUS files [REPLACED WITH "m_musicMode", DEPRECATED!!!] - //bool CartoonersVolumes; + bool m_runAtPcmRate; + //! Enable soft panning + bool m_softPanning; + + //! Just a padding. Reserved. + char _padding2[3]; + + /** + * @brief Music playing mode + */ enum MusicMode { + //! MIDI mode MODE_MIDI, + //! Id-Software Music mode MODE_IMF, + //! Creative Music Files mode MODE_CMF, + //! EA-MUS (a.k.a. RSXX) mode MODE_RSXX } m_musicMode; - //! Just a padding. Reserved. - char ___padding2[3]; - //! Volume models enum + + /** + * @brief Volume models enum + */ enum VolumesScale { + //! Generic volume model (linearization of logarithmic scale) VOLUME_Generic, + //! OPL3 native logarithmic scale VOLUME_NATIVE, + //! DMX volume scale logarithmic table VOLUME_DMX, + //! Apoge Sound System volume scaling model VOLUME_APOGEE, + //! Windows 9x driver volume scale table VOLUME_9X } m_volumeScale; + //! Reserved + char _padding3[8]; + + /** + * @brief Channel categiry enumeration + */ + enum ChanCat + { + //! Regular melodic/percussion channel + ChanCat_Regular = 0, + //! Four-op master + ChanCat_4op_Master = 1, + //! Four-op slave + ChanCat_4op_Slave = 2, + //! Rhythm-mode Bass drum + ChanCat_Rhythm_Bass = 3, + //! Rhythm-mode Snare drum + ChanCat_Rhythm_Snare = 4, + //! Rhythm-mode Tom-Tom + ChanCat_Rhythm_Tom = 5, + //! Rhythm-mode Cymbal + ChanCat_Rhythm_Cymbal = 6, + //! Rhythm-mode Hi-Hat + ChanCat_Rhythm_HiHat = 7, + //! Rhythm-mode Slave channel + ChanCat_Rhythm_Slave = 8 + }; + + //! Category of the channel + /*! 1 = quad-master, 2 = quad-slave, 0 = regular + 3 = percussion BassDrum + 4 = percussion Snare + 5 = percussion Tom + 6 = percussion Crash cymbal + 7 = percussion Hihat + 8 = percussion slave + */ + std::vector m_channelCategory; + + + /** + * @brief C.O. Constructor + */ OPL3(); - char ____padding3[8]; - std::vector four_op_category; // 1 = quad-master, 2 = quad-slave, 0 = regular - // 3 = percussion BassDrum - // 4 = percussion Snare - // 5 = percussion Tom - // 6 = percussion Crash cymbal - // 7 = percussion Hihat - // 8 = percussion slave - void Poke(size_t card, uint16_t index, uint8_t value); + /** + * @brief Checks are setup locked to be changed on the fly or not + * @return true when setup on the fly is locked + */ + bool setupLocked(); - void NoteOff(size_t c); - void NoteOn(unsigned c, double hertz); - void Touch_Real(unsigned c, unsigned volume, uint8_t brightness = 127); - //void Touch(unsigned c, unsigned volume) + /** + * @brief Choose one of embedded banks + * @param bank ID of the bank + */ + void setEmbeddedBank(uint32_t bank); + + /** + * @brief Write data to OPL3 chip register + * @param chip Index of emulated chip. In hardware OPL3 builds, this parameter is ignored + * @param address Register address to write + * @param value Value to write + */ + void writeReg(size_t chip, uint16_t address, uint8_t value); + + /** + * @brief Write data to OPL3 chip register + * @param chip Index of emulated chip. In hardware OPL3 builds, this parameter is ignored + * @param address Register address to write + * @param value Value to write + */ + void writeRegI(size_t chip, uint32_t address, uint32_t value); + + /** + * @brief Write to soft panning control of OPL3 chip emulator + * @param chip Index of emulated chip. + * @param address Register of channel to write + * @param value Value to write + */ + void writePan(size_t chip, uint32_t address, uint32_t value); + + /** + * @brief Off the note in specified chip channel + * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + */ + void noteOff(size_t c); + + /** + * @brief On the note in specified chip channel with specified frequency of the tone + * @param c1 Channel of chip [or master 4-op channel] (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param c2 Slave 4-op channel of chip, unused for 2op (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param hertz Frequency of the tone in hertzes + */ + void noteOn(size_t c1, size_t c2, double hertz); + + /** + * @brief Change setup of instrument in specified chip channel + * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param volume Volume level (from 0 to 63) + * @param brightness CC74 Brightness level (from 0 to 127) + */ + void touchNote(size_t c, uint8_t volume, uint8_t brightness = 127); + + /** + * @brief Set the instrument into specified chip channel + * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param instrument Instrument data to set into the chip channel + */ + void setPatch(size_t c, const adldata &instrument); + + /** + * @brief Set panpot position + * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param value 3-bit panpot value + */ + void setPan(size_t c, uint8_t value); + + /** + * @brief Shut up all chip channels + */ + void silenceAll(); + + /** + * @brief Commit updated flag states to chip registers + */ + void updateChannelCategories(); + + /** + * @brief commit deepTremolo and deepVibrato flags + */ + void commitDeepFlags(); + + /** + * @brief Set the volume scaling model + * @param volumeModel Type of volume scale model scale + */ + void setVolumeScaleModel(ADLMIDI_VolumeModels volumeModel); + + /** + * @brief Get the volume scaling model + */ + ADLMIDI_VolumeModels getVolumeScaleModel(); - void Patch(uint16_t c, const adldata &adli); - void Pan(unsigned c, unsigned value); - void Silence(); - void updateFlags(); - void updateDeepFlags(); - void ChangeVolumeRangesModel(ADLMIDI_VolumeModels volumeModel); #ifndef ADLMIDI_HW_OPL - void ClearChips(); + /** + * @brief Clean up all running emulated chip instances + */ + void clearChips(); #endif - void Reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler); + + /** + * @brief Reset chip properties and initialize them + * @param emulator Type of chip emulator + * @param PCM_RATE Output sample rate to generate on output + * @param audioTickHandler PCM-accurate clock hook + */ + void reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler); }; @@ -306,17 +492,11 @@ public: struct MIDIEventHooks { MIDIEventHooks() : - onEvent(NULL), - onEvent_userData(NULL), onNote(NULL), onNote_userData(NULL), onDebugMessage(NULL), onDebugMessage_userData(NULL) {} - //! Raw MIDI event hook - typedef void (*RawEventHook)(void *userdata, uint8_t type, uint8_t subtype, uint8_t channel, const uint8_t *data, size_t len); - RawEventHook onEvent; - void *onEvent_userData; //! Note on/off hooks typedef void (*NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend); @@ -334,207 +514,121 @@ class MIDIplay { friend void adl_reset(struct ADL_MIDIPlayer*); public: - MIDIplay(unsigned long sampleRate = 22050); + explicit MIDIplay(unsigned long sampleRate = 22050); ~MIDIplay() {} void applySetup(); + void partialReset(); + void resetMIDI(); + /**********************Internal structures and classes**********************/ /** - * @brief A little class gives able to read filedata from disk and also from a memory segment + * @brief Persistent settings for each MIDI channel */ - class fileReader - { - public: - enum relTo - { - SET = 0, - CUR = 1, - END = 2 - }; - - fileReader() - { - fp = NULL; - mp = NULL; - mp_size = 0; - mp_tell = 0; - } - ~fileReader() - { - close(); - } - - void openFile(const char *path) - { - #if !defined(_WIN32) || defined(__WATCOMC__) - fp = std::fopen(path, "rb"); - #else - wchar_t widePath[MAX_PATH]; - int size = MultiByteToWideChar(CP_UTF8, 0, path, (int)std::strlen(path), widePath, MAX_PATH); - widePath[size] = '\0'; - fp = _wfopen(widePath, L"rb"); - #endif - _fileName = path; - mp = NULL; - mp_size = 0; - mp_tell = 0; - } - - void openData(const void *mem, size_t lenght) - { - fp = NULL; - mp = mem; - mp_size = lenght; - mp_tell = 0; - } - - void seek(long pos, int rel_to) - { - if(fp) - std::fseek(fp, pos, rel_to); - else - { - switch(rel_to) - { - case SET: - mp_tell = static_cast(pos); - break; - - case END: - mp_tell = mp_size - static_cast(pos); - break; - - case CUR: - mp_tell = mp_tell + static_cast(pos); - break; - } - - if(mp_tell > mp_size) - mp_tell = mp_size; - } - } - - inline void seeku(uint64_t pos, int rel_to) - { - seek(static_cast(pos), rel_to); - } - - size_t read(void *buf, size_t num, size_t size) - { - if(fp) - return std::fread(buf, num, size, fp); - else - { - size_t pos = 0; - size_t maxSize = static_cast(size * num); - - while((pos < maxSize) && (mp_tell < mp_size)) - { - reinterpret_cast(buf)[pos] = reinterpret_cast(mp)[mp_tell]; - mp_tell++; - pos++; - } - - return pos; - } - } - - int getc() - { - if(fp) - return std::getc(fp); - else - { - if(mp_tell >= mp_size) return -1; - int x = reinterpret_cast(mp)[mp_tell]; - mp_tell++; - return x; - } - } - - size_t tell() - { - if(fp) - return static_cast(std::ftell(fp)); - else - return mp_tell; - } - - void close() - { - if(fp) std::fclose(fp); - - fp = NULL; - mp = NULL; - mp_size = 0; - mp_tell = 0; - } - - bool isValid() - { - return (fp) || (mp); - } - - bool eof() - { - if(fp) - return (std::feof(fp) != 0); - else - return mp_tell >= mp_size; - } - std::string _fileName; - std::FILE *fp; - const void *mp; - size_t mp_size; - size_t mp_tell; - }; - - // Persistent settings for each MIDI channel struct MIDIchannel { - uint16_t portamento; - uint8_t bank_lsb, bank_msb; + //! LSB Bank number + uint8_t bank_lsb, + //! MSB Bank number + bank_msb; + //! Current patch number uint8_t patch; - uint8_t volume, expression; - uint8_t panning, vibrato, aftertouch, sustain; + //! Volume level + uint8_t volume, + //! Expression level + expression; + //! Panning level + uint8_t panning, + //! Vibrato level + vibrato, + //! Channel aftertouch level + aftertouch; + //! Portamento time + uint16_t portamento; + //! Is Pedal sustain active + bool sustain; + //! Is Soft pedal active + bool softPedal; + //! Is portamento enabled + bool portamentoEnable; + //! Source note number used by portamento + int8_t portamentoSource; // note number or -1 + //! Portamento rate + double portamentoRate; //! Per note Aftertouch values uint8_t noteAftertouch[128]; //! Is note aftertouch has any non-zero value bool noteAfterTouchInUse; - char ____padding[6]; + //! Reserved + char _padding[6]; + //! Pitch bend value int bend; + //! Pitch bend sensitivity double bendsense; - int bendsense_lsb, bendsense_msb; - double vibpos, vibspeed, vibdepth; - int64_t vibdelay; - uint8_t lastlrpn, lastmrpn; + //! Pitch bend sensitivity LSB value + int bendsense_lsb, + //! Pitch bend sensitivity MSB value + bendsense_msb; + //! Vibrato position value + double vibpos, + //! Vibrato speed value + vibspeed, + //! Vibrato depth value + vibdepth; + //! Vibrato delay time + int64_t vibdelay_us; + //! Last LSB part of RPN value received + uint8_t lastlrpn, + //! Last MSB poart of RPN value received + lastmrpn; + //! Interpret RPN value as NRPN bool nrpn; + //! Brightness level uint8_t brightness; + + //! Is melodic channel turned into percussion bool is_xg_percussion; + + /** + * @brief Per-Note information + */ struct NoteInfo { + //! Note number uint8_t note; + //! Is note active bool active; - // Current pressure + //! Current pressure uint8_t vol; - // Note vibrato (a part of Note Aftertouch feature) + //! Note vibrato (a part of Note Aftertouch feature) uint8_t vibrato; - // Tone selected on noteon: - int16_t tone; - char ____padding2[4]; - // Patch selected on noteon; index to bank.ins[] + //! Tone selected on noteon: + int16_t noteTone; + //! Current tone (!= noteTone if gliding note) + double currentTone; + //! Gliding rate + double glideRate; + //! Patch selected on noteon; index to bank.ins[] size_t midiins; - // Patch selected + //! Is note the percussion instrument + bool isPercussion; + //! Note that plays missing instrument. Doesn't using any chip channels + bool isBlank; + //! Patch selected const adlinsdata2 *ains; enum { MaxNumPhysChans = 2, - MaxNumPhysItemCount = MaxNumPhysChans, + MaxNumPhysItemCount = MaxNumPhysChans }; + + /** + * @brief Reference to currently using chip channel + */ struct Phys { //! Destination chip channel @@ -558,11 +652,12 @@ public: return !operator==(oth); } }; + //! List of OPL3 channels it is currently occupying. Phys chip_channels[MaxNumPhysItemCount]; //! Count of used channels. unsigned chip_channels_count; - // + Phys *phys_find(unsigned chip_chan) { Phys *ph = NULL; @@ -603,20 +698,26 @@ public: phys_erase_at(ph); } }; - char ____padding2[5]; + + //! Reserved + char _padding2[5]; + //! Count of gliding notes in this channel + unsigned gliding_note_count; + + //! Active notes in the channel NoteInfo activenotes[128]; struct activenoteiterator { - explicit activenoteiterator(NoteInfo *info = 0) + explicit activenoteiterator(NoteInfo *info = NULL) : ptr(info) {} activenoteiterator &operator++() { if(ptr->note == 127) - ptr = 0; + ptr = NULL; else for(++ptr; ptr && !ptr->active;) - ptr = (ptr->note == 127) ? 0 : (ptr + 1); + ptr = (ptr->note == 127) ? NULL : (ptr + 1); return *this; } activenoteiterator operator++(int) @@ -649,7 +750,7 @@ public: { assert(note < 128); return activenoteiterator( - activenotes[note].active ? &activenotes[note] : 0); + activenotes[note].active ? &activenotes[note] : NULL); } activenoteiterator activenotes_ensure_find(uint8_t note) @@ -687,6 +788,9 @@ public: } } + /** + * @brief Reset channel into initial state + */ void reset() { resetAllControllers(); @@ -699,6 +803,10 @@ public: nrpn = false; is_xg_percussion = false; } + + /** + * @brief Reset all MIDI controllers into initial state + */ void resetAllControllers() { bend = 0; @@ -707,35 +815,52 @@ public: updateBendSensitivity(); volume = 100; expression = 127; - sustain = 0; + sustain = false; + softPedal = false; vibrato = 0; aftertouch = 0; std::memset(noteAftertouch, 0, 128); noteAfterTouchInUse = false; vibspeed = 2 * 3.141592653 * 5.0; vibdepth = 0.5 / 127; - vibdelay = 0; - panning = OPL_PANNING_BOTH; + vibdelay_us = 0; + panning = 64; portamento = 0; + portamentoEnable = false; + portamentoSource = -1; + portamentoRate = HUGE_VAL; brightness = 127; } + + /** + * @brief Has channel vibrato to process + * @return + */ bool hasVibrato() { return (vibrato > 0) || (aftertouch > 0) || noteAfterTouchInUse; } + + /** + * @brief Commit pitch bend sensitivity value from MSB and LSB + */ void updateBendSensitivity() { int cent = bendsense_msb * 128 + bendsense_lsb; bendsense = cent * (1.0 / (128 * 8192)); } + MIDIchannel() { activenotes_clear(); + gliding_note_count = 0; reset(); } }; - // Additional information about OPL3 channels + /** + * @brief Additional information about OPL3 channels + */ struct AdlChannel { struct Location @@ -751,18 +876,27 @@ public: { LocationData *prev, *next; Location loc; - bool sustained; - char ____padding[7]; + enum { + Sustain_None = 0x00, + Sustain_Pedal = 0x01, + Sustain_Sostenuto = 0x02, + Sustain_ANY = Sustain_Pedal | Sustain_Sostenuto + }; + uint32_t sustained; + char _padding[6]; MIDIchannel::NoteInfo::Phys ins; // a copy of that in phys[] //! Has fixed sustain, don't iterate "on" timeout bool fixed_sustain; //! Timeout until note will be allowed to be killed by channel manager while it is on - int64_t kon_time_until_neglible; - int64_t vibdelay; + int64_t kon_time_until_neglible_us; + int64_t vibdelay_us; }; - // If the channel is keyoff'd - int64_t koff_time_until_neglible; + //! Time left until sounding will be muted after key off + int64_t koff_time_until_neglible_us; + + //! Recently passed instrument, improves a goodness of released but busy channel when matching + MIDIchannel::NoteInfo::Phys recent_ins; enum { users_max = 128 }; LocationData *users_first, *users_free_cells; @@ -779,12 +913,13 @@ public: void users_assign(const LocationData *users, size_t count); // For channel allocation: - AdlChannel(): koff_time_until_neglible(0) + AdlChannel(): koff_time_until_neglible_us(0) { users_clear(); + std::memset(&recent_ins, 0, sizeof(MIDIchannel::NoteInfo::Phys)); } - AdlChannel(const AdlChannel &oth): koff_time_until_neglible(oth.koff_time_until_neglible) + AdlChannel(const AdlChannel &oth): koff_time_until_neglible_us(oth.koff_time_until_neglible_us) { if(oth.users_first) { @@ -797,156 +932,49 @@ public: AdlChannel &operator=(const AdlChannel &oth) { - koff_time_until_neglible = oth.koff_time_until_neglible; + koff_time_until_neglible_us = oth.koff_time_until_neglible_us; users_assign(oth.users_first, oth.users_size); return *this; } - void AddAge(int64_t ms); + /** + * @brief Increases age of active note in microseconds time + * @param us Amount time in microseconds + */ + void addAge(int64_t us); }; #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER /** - * @brief MIDI Event utility container + * @brief MIDI files player sequencer */ - class MidiEvent - { - public: - MidiEvent(); - - enum Types - { - T_UNKNOWN = 0x00, - T_NOTEOFF = 0x08,//size == 2 - T_NOTEON = 0x09,//size == 2 - T_NOTETOUCH = 0x0A,//size == 2 - T_CTRLCHANGE = 0x0B,//size == 2 - T_PATCHCHANGE = 0x0C,//size == 1 - T_CHANAFTTOUCH = 0x0D,//size == 1 - T_WHEEL = 0x0E,//size == 2 - - T_SYSEX = 0xF0,//size == len - T_SYSCOMSPOSPTR = 0xF2,//size == 2 - T_SYSCOMSNGSEL = 0xF3,//size == 1 - T_SYSEX2 = 0xF7,//size == len - T_SPECIAL = 0xFF - }; - enum SubTypes - { - ST_SEQNUMBER = 0x00,//size == 2 - ST_TEXT = 0x01,//size == len - ST_COPYRIGHT = 0x02,//size == len - ST_SQTRKTITLE = 0x03,//size == len - ST_INSTRTITLE = 0x04,//size == len - ST_LYRICS = 0x05,//size == len - ST_MARKER = 0x06,//size == len - ST_CUEPOINT = 0x07,//size == len - ST_DEVICESWITCH = 0x09,//size == len - ST_MIDICHPREFIX = 0x20,//size == 1 - - ST_ENDTRACK = 0x2F,//size == 0 - ST_TEMPOCHANGE = 0x51,//size == 3 - ST_SMPTEOFFSET = 0x54,//size == 5 - ST_TIMESIGNATURE = 0x55, //size == 4 - ST_KEYSIGNATURE = 0x59,//size == 2 - ST_SEQUENCERSPEC = 0x7F, //size == len - - /* Non-standard, internal ADLMIDI usage only */ - ST_LOOPSTART = 0xE1,//size == 0 - ST_LOOPEND = 0xE2,//size == 0 - ST_RAWOPL = 0xE3//size == 0 - }; - //! Main type of event - uint8_t type; - //! Sub-type of the event - uint8_t subtype; - //! Targeted MIDI channel - uint8_t channel; - //! Is valid event - uint8_t isValid; - //! Reserved 5 bytes padding - uint8_t __padding[4]; - //! Absolute tick position (Used for the tempo calculation only) - uint64_t absPosition; - //! Raw data of this event - std::vector data; - }; + MidiSequencer m_sequencer; /** - * @brief A track position event contains a chain of MIDI events until next delay value - * - * Created with purpose to sort events by type in the same position - * (for example, to keep controllers always first than note on events or lower than note-off events) + * @brief Interface between MIDI sequencer and this library */ - class MidiTrackRow - { - public: - MidiTrackRow(); - void reset(); - //! Absolute time position in seconds - double time; - //! Delay to next event in ticks - uint64_t delay; - //! Absolute position in ticks - uint64_t absPos; - //! Delay to next event in seconds - double timeDelay; - std::vector events; - /** - * @brief Sort events in this position - */ - void sortEvents(bool *noteStates = NULL); - }; + BW_MidiRtInterface m_sequencerInterface; /** - * @brief Tempo change point entry. Used in the MIDI data building function only. + * @brief Initialize MIDI sequencer interface */ - struct TempoChangePoint - { - uint64_t absPos; - fraction tempo; - }; - //P.S. I declared it here instead of local in-function because C++99 can't process templates with locally-declared structures - - typedef std::list MidiTrackQueue; - - // Information about each track - struct PositionNew - { - bool began; - char padding[7]; - double wait; - double absTimePosition; - struct TrackInfo - { - size_t ptr; - uint64_t delay; - int status; - char padding2[4]; - MidiTrackQueue::iterator pos; - TrackInfo(): ptr(0), delay(0), status(0) {} - }; - std::vector track; - PositionNew(): began(false), wait(0.0), absTimePosition(0.0), track() - {} - }; -#endif//ADLMIDI_DISABLE_MIDI_SEQUENCER + void initSequencerInterface(); +#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER struct Setup { int emulator; bool runAtPcmRate; - unsigned int AdlBank; - unsigned int NumFourOps; - unsigned int NumCards; - int HighTremoloMode; - int HighVibratoMode; - int AdlPercussionMode; - bool LogarithmicVolumes; - int VolumeModel; + unsigned int bankId; + int numFourOps; + unsigned int numChips; + int deepTremoloMode; + int deepVibratoMode; + int rhythmMode; + bool logarithmicVolumes; + int volumeScaleModel; //unsigned int SkipForward; - bool loopingIsEnabled; - int ScaleModulators; + int scaleModulators; bool fullRangeBrightnessCC74; double delay; @@ -964,148 +992,140 @@ public: unsigned long PCM_RATE; }; + /** + * @brief MIDI Marker entry + */ struct MIDI_MarkerEntry { + //! Label of marker std::string label; + //! Absolute position in seconds double pos_time; + //! Absolute position in ticks in the track uint64_t pos_ticks; }; - std::vector Ch; - bool cmf_percussion_mode; + //! Available MIDI Channels + std::vector m_midiChannels; + //! CMF Rhythm mode + bool m_cmfPercussionMode; + + //! Master volume, controlled via SysEx + uint8_t m_masterVolume; + + //! SysEx device ID + uint8_t m_sysExDeviceId; + + /** + * @brief MIDI Synthesizer mode + */ + enum SynthMode + { + Mode_GM = 0x00, + Mode_GS = 0x01, + Mode_XG = 0x02, + Mode_GM2 = 0x04 + }; + //! MIDI Synthesizer mode + uint32_t m_synthMode; + + //! Installed function hooks MIDIEventHooks hooks; private: - std::map devices; - std::map current_device; + //! Per-track MIDI devices map + std::map m_midiDevices; + //! Current MIDI device per track + std::map m_currentMidiDevice; - //Padding to fix CLanc code model's warning - char ____padding[7]; + //! Padding to fix CLanc code model's warning + char _padding[7]; - std::vector ch; + //! Chip channels map + std::vector m_chipChannels; //! Counter of arpeggio processing size_t m_arpeggioCounter; +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) //! Audio tick counter uint32_t m_audioTickCounter; - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - std::vector > TrackData; - - PositionNew CurrentPositionNew, LoopBeginPositionNew, trackBeginPositionNew; - - //! Full song length in seconds - double fullSongTimeLength; - //! Delay after song playd before rejecting the output stream requests - double postSongWaitDelay; - - //! Loop start time - double loopStartTime; - //! Loop end time - double loopEndTime; #endif - //! Local error string - std::string errorString; + //! Local error string std::string errorStringOut; -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - //! Pre-processed track data storage - std::vector trackDataNew; -#endif - //! Missing instruments catches - std::set caugh_missing_instruments; + std::set caugh_missing_instruments; //! Missing melodic banks catches - std::set caugh_missing_banks_melodic; + std::set caugh_missing_banks_melodic; //! Missing percussion banks catches - std::set caugh_missing_banks_percussion; - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - /** - * @brief Build MIDI track data from the raw track data storage - * @return true if everything successfully processed, or false on any error - */ - bool buildTrackData(); - - /** - * @brief Parse one event from raw MIDI track stream - * @param [_inout] ptr pointer to pointer to current position on the raw data track - * @param [_in] end address to end of raw track data, needed to validate position and size - * @param [_inout] status status of the track processing - * @return Parsed MIDI event entry - */ - MidiEvent parseEvent(uint8_t **ptr, uint8_t *end, int &status); -#endif//ADLMIDI_DISABLE_MIDI_SEQUENCER + std::set caugh_missing_banks_percussion; public: const std::string &getErrorString(); void setErrorString(const std::string &err); -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - std::string musTitle; - std::string musCopyright; - std::vector musTrackTitles; - std::vector musMarkers; + //! OPL3 Chip manager + OPL3 m_synth; - fraction InvDeltaTicks, Tempo; - //! Tempo multiplier - double tempoMultiplier; - bool atEnd, - loopStart, - loopEnd, - invalidLoop; /*Loop points are invalid (loopStart after loopEnd or loopStart and loopEnd are on same place)*/ - char ____padding2[2]; -#endif - OPL3 opl; - - int32_t outBuf[1024]; + //! Generator output buffer + int32_t m_outBuf[1024]; + //! Synthesizer setup Setup m_setup; -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER /** - * @brief Utility function to read Big-Endian integer from raw binary data - * @param buffer Pointer to raw binary buffer - * @param nbytes Count of bytes to parse integer - * @return Extracted unsigned integer + * @brief Load custom bank from file + * @param filename Path to bank file + * @return true on succes */ - static uint64_t ReadBEint(const void *buffer, size_t nbytes); - - /** - * @brief Utility function to read Little-Endian integer from raw binary data - * @param buffer Pointer to raw binary buffer - * @param nbytes Count of bytes to parse integer - * @return Extracted unsigned integer - */ - static uint64_t ReadLEint(const void *buffer, size_t nbytes); - - /** - * @brief Standard MIDI Variable-Length numeric value parser without of validation - * @param [_inout] ptr Pointer to memory block that contains begin of variable-length value - * @return Unsigned integer that conains parsed variable-length value - */ - uint64_t ReadVarLen(uint8_t **ptr); - /** - * @brief Secure Standard MIDI Variable-Length numeric value parser with anti-out-of-range protection - * @param [_inout] ptr Pointer to memory block that contains begin of variable-length value, will be iterated forward - * @param [_in end Pointer to end of memory block where variable-length value is stored (after end of track) - * @param [_out] ok Reference to boolean which takes result of variable-length value parsing - * @return Unsigned integer that conains parsed variable-length value - */ - uint64_t ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok); -#endif - bool LoadBank(const std::string &filename); + + /** + * @brief Load custom bank from memory block + * @param data Pointer to memory block where raw bank file is stored + * @param size Size of given memory block + * @return true on succes + */ bool LoadBank(const void *data, size_t size); - bool LoadBank(fileReader &fr); + + /** + * @brief Load custom bank from opened FileAndMemReader class + * @param fr Instance with opened file + * @return true on succes + */ + bool LoadBank(FileAndMemReader &fr); #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER + /** + * @brief MIDI file loading pre-process + * @return true on success, false on failure + */ + bool LoadMIDI_pre(); + + /** + * @brief MIDI file loading post-process + * @return true on success, false on failure + */ + bool LoadMIDI_post(); + + /** + * @brief Load music file from a file + * @param filename Path to music file + * @return true on success, false on failure + */ + bool LoadMIDI(const std::string &filename); + + /** + * @brief Load music file from the memory block + * @param data pointer to the memory block + * @param size size of memory block + * @return true on success, false on failure + */ bool LoadMIDI(const void *data, size_t size); - bool LoadMIDI(fileReader &fr); /** * @brief Periodic tick handler. @@ -1114,83 +1134,212 @@ public: * @return desired number of seconds until next call */ double Tick(double s, double granularity); -#endif +#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER /** * @brief Process extra iterators like vibrato or arpeggio * @param s seconds since last call */ - void TickIteratos(double s); + void TickIterators(double s); -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - /** - * @brief Change current position to specified time position in seconds - * @param seconds Absolute time position in seconds - */ - void seek(double seconds); - - /** - * @brief Gives current time position in seconds - * @return Current time position in seconds - */ - double tell(); - - /** - * @brief Gives time length of current song in seconds - * @return Time length of current song in seconds - */ - double timeLength(); - - /** - * @brief Gives loop start time position in seconds - * @return Loop start time position in seconds or -1 if song has no loop points - */ - double getLoopStart(); - - /** - * @brief Gives loop end time position in seconds - * @return Loop end time position in seconds or -1 if song has no loop points - */ - double getLoopEnd(); - - /** - * @brief Return to begin of current song - */ - void rewind(); - - /** - * @brief Set tempo multiplier - * @param tempo Tempo multiplier: 1.0 - original tempo. >1 - faster, <1 - slower - */ - void setTempo(double tempo); -#endif//ADLMIDI_DISABLE_MIDI_SEQUENCER /* RealTime event triggers */ + /** + * @brief Reset state of all channels + */ void realTime_ResetState(); + /** + * @brief Note On event + * @param channel MIDI channel + * @param note Note key (from 0 to 127) + * @param velocity Velocity level (from 0 to 127) + * @return true if Note On event was accepted + */ bool realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity); + + /** + * @brief Note Off event + * @param channel MIDI channel + * @param note Note key (from 0 to 127) + */ void realTime_NoteOff(uint8_t channel, uint8_t note); + /** + * @brief Note aftertouch event + * @param channel MIDI channel + * @param note Note key (from 0 to 127) + * @param atVal After-Touch level (from 0 to 127) + */ void realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal); + + /** + * @brief Channel aftertouch event + * @param channel MIDI channel + * @param atVal After-Touch level (from 0 to 127) + */ void realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal); + /** + * @brief Controller Change event + * @param channel MIDI channel + * @param type Type of controller + * @param value Value of the controller (from 0 to 127) + */ void realTime_Controller(uint8_t channel, uint8_t type, uint8_t value); + /** + * @brief Patch change + * @param channel MIDI channel + * @param patch Patch Number (from 0 to 127) + */ void realTime_PatchChange(uint8_t channel, uint8_t patch); + /** + * @brief Pitch bend change + * @param channel MIDI channel + * @param pitch Concoctated raw pitch value + */ void realTime_PitchBend(uint8_t channel, uint16_t pitch); + + /** + * @brief Pitch bend change + * @param channel MIDI channel + * @param msb MSB of pitch value + * @param lsb LSB of pitch value + */ void realTime_PitchBend(uint8_t channel, uint8_t msb, uint8_t lsb); + /** + * @brief LSB Bank Change CC + * @param channel MIDI channel + * @param lsb LSB value of bank number + */ void realTime_BankChangeLSB(uint8_t channel, uint8_t lsb); + + /** + * @brief MSB Bank Change CC + * @param channel MIDI channel + * @param msb MSB value of bank number + */ void realTime_BankChangeMSB(uint8_t channel, uint8_t msb); + + /** + * @brief Bank Change (united value) + * @param channel MIDI channel + * @param bank Bank number value + */ void realTime_BankChange(uint8_t channel, uint16_t bank); + /** + * @brief Sets the Device identifier + * @param id 7-bit Device identifier + */ + void setDeviceId(uint8_t id); + + /** + * @brief System Exclusive message + * @param msg Raw SysEx Message + * @param size Length of SysEx message + * @return true if message was passed successfully. False on any errors + */ + bool realTime_SysEx(const uint8_t *msg, size_t size); + + /** + * @brief Turn off all notes and mute the sound of releasing notes + */ void realTime_panic(); + /** + * @brief Device switch (to extend 16-channels limit of MIDI standard) + * @param track MIDI track index + * @param data Device name + * @param length Length of device name string + */ + void realTime_deviceSwitch(size_t track, const char *data, size_t length); + + /** + * @brief Currently selected device index + * @param track MIDI track index + * @return Multiple 16 value + */ + size_t realTime_currentDevice(size_t track); + + /** + * @brief Send raw OPL chip command + * @param reg OPL Register + * @param value Value to write + */ + void realTime_rawOPL(uint8_t reg, uint8_t value); + +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) // Audio rate tick handler void AudioTick(uint32_t chipId, uint32_t rate); +#endif private: + /** + * @brief Hardware manufacturer (Used for SysEx) + */ + enum + { + Manufacturer_Roland = 0x41, + Manufacturer_Yamaha = 0x43, + Manufacturer_UniversalNonRealtime = 0x7E, + Manufacturer_UniversalRealtime = 0x7F + }; + + /** + * @brief Roland Mode (Used for SysEx) + */ + enum + { + RolandMode_Request = 0x11, + RolandMode_Send = 0x12 + }; + + /** + * @brief Device model (Used for SysEx) + */ + enum + { + RolandModel_GS = 0x42, + RolandModel_SC55 = 0x45, + YamahaModel_XG = 0x4C + }; + + /** + * @brief Process generic SysEx events + * @param dev Device ID + * @param realtime Is real-time event + * @param data Raw SysEx data + * @param size Size of given SysEx data + * @return true when event was successfully handled + */ + bool doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size); + + /** + * @brief Process events specific to Roland devices + * @param dev Device ID + * @param data Raw SysEx data + * @param size Size of given SysEx data + * @return true when event was successfully handled + */ + bool doRolandSysEx(unsigned dev, const uint8_t *data, size_t size); + + /** + * @brief Process events specific to Yamaha devices + * @param dev Device ID + * @param data Raw SysEx data + * @param size Size of given SysEx data + * @return true when event was successfully handled + */ + bool doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size); + +private: + /** + * @brief Note Update properties + */ enum { Upd_Patch = 0x1, @@ -1200,43 +1349,129 @@ private: Upd_All = Upd_Pan + Upd_Volume + Upd_Pitch, Upd_Off = 0x20, Upd_Mute = 0x40, - Upt_OffMute = Upd_Off + Upd_Mute + Upd_OffMute = Upd_Off + Upd_Mute }; - void NoteUpdate(uint16_t MidCh, + /** + * @brief Update active note + * @param MidCh MIDI Channel where note is processing + * @param i Iterator that points to active note in the MIDI channel + * @param props_mask Properties to update + * @param select_adlchn Specify chip channel, or -1 - all chip channels used by the note + */ + void noteUpdate(size_t midCh, MIDIchannel::activenoteiterator i, unsigned props_mask, int32_t select_adlchn = -1); -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - bool ProcessEventsNew(bool isSeek = false); - void HandleEvent(size_t tk, const MidiEvent &evt, int &status); -#endif + /** + * @brief Update all notes in specified MIDI channel + * @param midCh MIDI channel to update all notes in it + * @param props_mask Properties to update + */ + void noteUpdateAll(size_t midCh, unsigned props_mask); - // Determine how good a candidate this adlchannel - // would be for playing a note from this instrument. - int64_t CalculateAdlChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins, uint16_t /*MidCh*/) const; + /** + * @brief Determine how good a candidate this adlchannel would be for playing a note from this instrument. + * @param c Wanted chip channel + * @param ins Instrument wanted to be used in this channel + * @return Calculated coodness points + */ + int64_t calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const; - // A new note will be played on this channel using this instrument. - // Kill existing notes on this channel (or don't, if we do arpeggio) - void PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins); + /** + * @brief A new note will be played on this channel using this instrument. + * @param c Wanted chip channel + * @param ins Instrument wanted to be used in this channel + * Kill existing notes on this channel (or don't, if we do arpeggio) + */ + void prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins); - void KillOrEvacuate( + /** + * @brief Kills note that uses wanted channel. When arpeggio is possible, note is evaluating to another channel + * @param from_channel Wanted chip channel + * @param j Chip channel instance + * @param i MIDI Channel active note instance + */ + void killOrEvacuate( size_t from_channel, AdlChannel::LocationData *j, MIDIchannel::activenoteiterator i); - void Panic(); - void KillSustainingNotes(int32_t MidCh = -1, int32_t this_adlchn = -1); - void SetRPN(unsigned MidCh, unsigned value, bool MSB); - //void UpdatePortamento(unsigned MidCh) - void NoteUpdate_All(uint16_t MidCh, unsigned props_mask); - void NoteOff(uint16_t MidCh, uint8_t note); - void UpdateVibrato(double amount); - void UpdateArpeggio(double /*amount*/); + /** + * @brief Off all notes and silence sound + */ + void panic(); + + /** + * @brief Kill note, sustaining by pedal or sostenuto + * @param MidCh MIDI channel, -1 - all MIDI channels + * @param this_adlchn Chip channel, -1 - all chip channels + * @param sustain_type Type of systain to process + */ + void killSustainingNotes(int32_t midCh = -1, + int32_t this_adlchn = -1, + uint32_t sustain_type = AdlChannel::LocationData::Sustain_ANY); + /** + * @brief Find active notes and mark them as sostenuto-sustained + * @param MidCh MIDI channel, -1 - all MIDI channels + */ + void markSostenutoNotes(int32_t midCh = -1); + + /** + * @brief Set RPN event value + * @param MidCh MIDI channel + * @param value 1 byte part of RPN value + * @param MSB is MSB or LSB part of value + */ + void setRPN(size_t midCh, unsigned value, bool MSB); + + /** + * @brief Update portamento setup in MIDI channel + * @param midCh MIDI channel where portamento needed to be updated + */ + void updatePortamento(size_t midCh); + + /** + * @brief Off the note + * @param midCh MIDI channel + * @param note Note to off + */ + void noteOff(size_t midCh, uint8_t note); + + /** + * @brief Update processing of vibrato to amount of seconds + * @param amount Amount value in seconds + */ + void updateVibrato(double amount); + + /** + * @brief Update auto-arpeggio + * @param amount Amount value in seconds [UNUSED] + */ + void updateArpeggio(double /*amount*/); + + /** + * @brief Update Portamento gliding to amount of seconds + * @param amount Amount value in seconds + */ + void updateGlide(double amount); public: - uint64_t ChooseDevice(const std::string &name); + /** + * @brief Checks was device name used or not + * @param name Name of MIDI device + * @return Offset of the MIDI Channels, multiple to 16 + */ + size_t chooseDevice(const std::string &name); + + /** + * @brief Gets a textual description of the state of chip channels + * @param text character pointer for text + * @param attr character pointer for text attributes + * @param size number of characters available to write + */ + void describeChannels(char *text, char *attr, size_t size); }; // I think, this is useless inside of Library @@ -1258,8 +1493,35 @@ struct FourChars }; */ +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) extern void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate); -extern int adlRefreshNumCards(ADL_MIDIPlayer *device); +#endif +/** + * @brief Automatically calculate and enable necessary count of 4-op channels on emulated chips + * @param device Library context + * @param silent Don't re-count channel categories + * @return Always 0 + */ +extern int adlCalculateFourOpChannels(MIDIplay *play, bool silent = false); + +/** + * @brief Check emulator availability + * @param emulator Emulator ID (ADL_Emulator) + * @return true when emulator is available + */ +extern bool adl_isEmulatorAvailable(int emulator); + +/** + * @brief Find highest emulator + * @return The ADL_Emulator enum value which contains ID of highest emulator + */ +extern int adl_getHighestEmulator(); + +/** + * @brief Find lowest emulator + * @return The ADL_Emulator enum value which contains ID of lowest emulator + */ +extern int adl_getLowestEmulator(); #endif // ADLMIDI_PRIVATE_HPP diff --git a/src/sound/adlmidi/chips/dosbox/dbopl.cpp b/src/sound/adlmidi/chips/dosbox/dbopl.cpp index 7d78c5f05..193120397 100644 --- a/src/sound/adlmidi/chips/dosbox/dbopl.cpp +++ b/src/sound/adlmidi/chips/dosbox/dbopl.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include "dbopl.h" #if defined(__GNUC__) && __GNUC__ > 3 @@ -70,6 +72,37 @@ #define PI 3.14159265358979323846 #endif +struct NoCopy { + NoCopy() {} +private: + NoCopy(const NoCopy &); + NoCopy &operator=(const NoCopy &); +}; +#if !defined(_WIN32) +#include +struct Mutex : NoCopy { + Mutex() { pthread_mutex_init(&m, NULL);} + ~Mutex() { pthread_mutex_destroy(&m); } + void lock() { pthread_mutex_lock(&m); } + void unlock() { pthread_mutex_unlock(&m); } + pthread_mutex_t m; +}; +#else +#include +struct Mutex : NoCopy { + Mutex() { InitializeCriticalSection(&m); } + ~Mutex() { DeleteCriticalSection(&m); } + void lock() { EnterCriticalSection(&m); } + void unlock() { LeaveCriticalSection(&m); } + CRITICAL_SECTION m; +}; +#endif +struct MutexHolder : NoCopy { + explicit MutexHolder(Mutex &m) : m(m) { m.lock(); } + ~MutexHolder() { m.unlock(); } + Mutex &m; +}; + namespace DBOPL { #define OPLRATE ((double)(14318180.0 / 288.0)) @@ -219,6 +252,29 @@ static const Bit8u KslShiftTable[4] = { 31,1,2,0 }; +// Pan law table +static const Bit16u PanLawTable[] = +{ + 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, + 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, + 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, + 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, + 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, + 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, + 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, + 50433, 49912, 49383, 48846, 48302, 47750, 47191, + 46340, /* Center left */ + 46340, /* Center right */ + 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, + 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, + 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, + 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, + 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, + 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, + 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, + 4858, 4050, 3240, 2431, 1620, 810, 0 +}; + //Generate a table index and table shift value using input value from a selected rate static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) { if ( val < 13 * 4 ) { //Rate 0 - 12 @@ -442,6 +498,7 @@ Bits Operator::TemplateVolume( ) { return vol; } //In sustain phase, but not sustaining, do regular release + /* fall through */ case RELEASE: vol += RateForward( releaseAdd );; if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { @@ -757,6 +814,11 @@ void Channel::WriteC0(const Chip* chip, Bit8u val) { UpdateSynth(chip); } +void Channel::WritePan(Bit8u val) { + panLeft = PanLawTable[val & 0x7F]; + panRight = PanLawTable[0x7F - (val & 0x7F)]; +} + void Channel::UpdateSynth( const Chip* chip ) { //Select the new synth mode if ( chip->opl3Active ) { @@ -971,8 +1033,8 @@ Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { case sm3AMFM: case sm3FMAM: case sm3AMAM: - output[ i * 2 + 0 ] += sample & maskLeft; - output[ i * 2 + 1 ] += sample & maskRight; + output[ i * 2 + 0 ] += (sample * panLeft / 65535) & maskLeft; + output[ i * 2 + 1 ] += (sample * panRight / 65535) & maskRight; break; default: break; @@ -1265,21 +1327,56 @@ void Chip::GenerateBlock3_Mix( Bitu total, Bit32s* output ) { } } -void Chip::Setup( Bit32u rate ) { +struct CacheEntry { + Bit32u rate; + Bit32u freqMul[16]; + Bit32u linearRates[76]; + Bit32u attackRates[76]; +}; +struct Cache : NoCopy { + ~Cache(); + Mutex mutex; + std::vector entries; +}; + +static Cache cache; + +Cache::~Cache() +{ + for ( size_t i = 0, n = entries.size(); i < n; ++i ) + delete entries[i]; +} + +static const CacheEntry *CacheLookupRateDependent( Bit32u rate ) +{ + for ( size_t i = 0, n = cache.entries.size(); i < n; ++i ) { + const CacheEntry *entry = cache.entries[i]; + if (entry->rate == rate) + return entry; + } + return NULL; +} + +static const CacheEntry &ComputeRateDependent( Bit32u rate ) +{ + { + MutexHolder lock( cache.mutex ); + if (const CacheEntry *entry = CacheLookupRateDependent( rate )) + return *entry; + } + double original = OPLRATE; -// double original = rate; double scale = original / (double)rate; - //Noise counter is run at the same precision as general waves - noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - noiseCounter = 0; - noiseValue = 1; //Make sure it triggers the noise xor the first time - //The low frequency oscillation counter - //Every time his overflows vibrato and tremoloindex are increased - lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - lfoCounter = 0; - vibratoIndex = 0; - tremoloIndex = 0; +#if __cplusplus >= 201103L + std::unique_ptr entry(new CacheEntry); +#else + std::auto_ptr entry(new CacheEntry); +#endif + entry->rate = rate; + Bit32u *freqMul = entry->freqMul; + Bit32u *linearRates = entry->linearRates; + Bit32u *attackRates = entry->attackRates; //With higher octave this gets shifted up //-1 since the freqCreateTable = *2 @@ -1301,6 +1398,7 @@ void Chip::Setup( Bit32u rate ) { EnvelopeSelect( i, index, shift ); linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); } + // Bit32s attackDiffs[62]; //Generate the best matching attack rate for ( Bit8u i = 0; i < 62; i++ ) { @@ -1353,6 +1451,36 @@ void Chip::Setup( Bit32u rate ) { //This should provide instant volume maximizing attackRates[i] = 8 << RATE_SH; } + + MutexHolder lock( cache.mutex ); + if (const CacheEntry *entry = CacheLookupRateDependent( rate )) + return *entry; + + cache.entries.push_back(entry.get()); + return *entry.release(); +} + +void Chip::Setup( Bit32u rate ) { + double original = OPLRATE; +// double original = rate; + double scale = original / (double)rate; + + //Noise counter is run at the same precision as general waves + noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); + noiseCounter = 0; + noiseValue = 1; //Make sure it triggers the noise xor the first time + //The low frequency oscillation counter + //Every time his overflows vibrato and tremoloindex are increased + lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); + lfoCounter = 0; + vibratoIndex = 0; + tremoloIndex = 0; + + const CacheEntry &entry = ComputeRateDependent( rate ); + freqMul = entry.freqMul; + linearRates = entry.linearRates; + attackRates = entry.attackRates; + //Setup the channels with the correct four op flags //Channels are accessed through a table so they appear linear here chan[ 0].fourMask = 0x00 | ( 1 << 0 ); @@ -1388,6 +1516,10 @@ void Chip::Setup( Bit32u rate ) { WriteReg( i, 0xff ); WriteReg( i, 0x0 ); } + + for ( int i = 0; i < 18; i++ ) { + chan[i].WritePan( 0x40 ); + } } static bool doneTables = false; @@ -1614,5 +1746,14 @@ void Handler::Init( Bitu rate ) { chip.Setup( static_cast(rate) ); } +void Handler::WritePan( Bit32u reg, Bit8u val ) +{ + Bitu index; + index = ((reg >> 4) & 0x10) | (reg & 0xf); + if (ChanOffsetTable[index]) { + Channel* regChan = (Channel*)(((char *)&chip) + ChanOffsetTable[index]); + regChan->WritePan(val); + } +} } //Namespace DBOPL diff --git a/src/sound/adlmidi/chips/dosbox/dbopl.h b/src/sound/adlmidi/chips/dosbox/dbopl.h index 73c0aa9a1..89d2019c9 100644 --- a/src/sound/adlmidi/chips/dosbox/dbopl.h +++ b/src/sound/adlmidi/chips/dosbox/dbopl.h @@ -75,13 +75,13 @@ typedef enum { sm3AMAM, sm6Start, sm2Percussion, - sm3Percussion, + sm3Percussion } SynthMode; //Shifts for the values contained in chandata variable enum { SHIFT_KSLBASE = 16, - SHIFT_KEYCODE = 24, + SHIFT_KEYCODE = 24 }; struct Operator { @@ -91,7 +91,7 @@ public: MASK_KSR = 0x10, MASK_SUSTAIN = 0x20, MASK_VIBRATO = 0x40, - MASK_TREMOLO = 0x80, + MASK_TREMOLO = 0x80 }; typedef enum { @@ -99,7 +99,7 @@ public: RELEASE, SUSTAIN, DECAY, - ATTACK, + ATTACK } State; VolumeHandler volHandler; @@ -192,6 +192,9 @@ struct Channel { Bit8s maskLeft; //Sign extended values for both channel's panning Bit8s maskRight; + Bit16u panLeft; // Extended behavior, scale values for soft panning + Bit16u panRight; + //Forward the channel data to the operators of the channel void SetChanData( const Chip* chip, Bit32u data ); //Change in the chandata, check for new values and if we have to forward to operators @@ -201,6 +204,8 @@ struct Channel { void WriteB0( const Chip* chip, Bit8u val ); void WriteC0( const Chip* chip, Bit8u val ); + void WritePan( Bit8u val ); + //call this for the first channel template< bool opl3Mode > void GeneratePercussion( Chip* chip, Bit32s* output ); @@ -222,11 +227,11 @@ struct Chip { Bit32u noiseValue; //Frequency scales for the different multiplications - Bit32u freqMul[16]; + const Bit32u *freqMul/*[16]*/; //Rates for decay and release for rate of this chip - Bit32u linearRates[76]; + const Bit32u *linearRates/*[76]*/; //Best match attack rates for the rate of this chip - Bit32u attackRates[76]; + const Bit32u *attackRates/*[76]*/; //18 channels with 2 operators each Channel chan[18]; @@ -271,6 +276,7 @@ struct Chip { struct Handler { DBOPL::Chip chip; + void WritePan( Bit32u port, Bit8u val ); Bit32u WriteAddr( Bit32u port, Bit8u val ); void WriteReg( Bit32u addr, Bit8u val ); void GenerateArr(Bit32s *out, Bitu *samples); diff --git a/src/sound/adlmidi/chips/dosbox_opl3.cpp b/src/sound/adlmidi/chips/dosbox_opl3.cpp index 30fa38ea5..0b9501fdc 100644 --- a/src/sound/adlmidi/chips/dosbox_opl3.cpp +++ b/src/sound/adlmidi/chips/dosbox_opl3.cpp @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPL3 (YMF262) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include "dosbox_opl3.h" #include "dosbox/dbopl.h" #include @@ -41,6 +61,12 @@ void DosBoxOPL3::writeReg(uint16_t addr, uint8_t data) chip_r->WriteReg(static_cast(addr), data); } +void DosBoxOPL3::writePan(uint16_t addr, uint8_t data) +{ + DBOPL::Handler *chip_r = reinterpret_cast(m_chip); + chip_r->WritePan(static_cast(addr), data); +} + void DosBoxOPL3::nativeGenerateN(int16_t *output, size_t frames) { DBOPL::Handler *chip_r = reinterpret_cast(m_chip); @@ -50,5 +76,5 @@ void DosBoxOPL3::nativeGenerateN(int16_t *output, size_t frames) const char *DosBoxOPL3::emulatorName() { - return "DosBox 0.74-r4111 OPL3"; + return "DOSBox 0.74-r4111 OPL3"; } diff --git a/src/sound/adlmidi/chips/dosbox_opl3.h b/src/sound/adlmidi/chips/dosbox_opl3.h index 192802666..eb79300f1 100644 --- a/src/sound/adlmidi/chips/dosbox_opl3.h +++ b/src/sound/adlmidi/chips/dosbox_opl3.h @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPL3 (YMF262) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef DOSBOX_OPL3_H #define DOSBOX_OPL3_H @@ -14,6 +34,7 @@ public: void setRate(uint32_t rate) override; void reset() override; void writeReg(uint16_t addr, uint8_t data) override; + void writePan(uint16_t addr, uint8_t data) override; void nativePreGenerate() override {} void nativePostGenerate() override {} void nativeGenerateN(int16_t *output, size_t frames) override; diff --git a/src/sound/adlmidi/chips/nuked/nukedopl3.c b/src/sound/adlmidi/chips/nuked/nukedopl3.c index 87d321257..267e67ae4 100644 --- a/src/sound/adlmidi/chips/nuked/nukedopl3.c +++ b/src/sound/adlmidi/chips/nuked/nukedopl3.c @@ -1,16 +1,19 @@ /* * Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Nuked OPL3 emulator. * Thanks: @@ -174,6 +177,32 @@ static const Bit8u ch_slot[18] = { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 }; +/* + * Pan law table + */ + +static const Bit16u panlawtable[] = +{ + 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, + 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, + 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, + 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, + 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, + 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, + 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, + 50433, 49912, 49383, 48846, 48302, 47750, 47191, + 46340, /* Center left */ + 46340, /* Center right */ + 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, + 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, + 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, + 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, + 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, + 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, + 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, + 4858, 4050, 3240, 2431, 1620, 810, 0 +}; + /* * Envelope generator */ @@ -1068,7 +1097,7 @@ void OPL3_Generate(opl3_chip *chip, Bit16s *buf) { accm += *chip->channel[ii].out[jj]; } - chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); + chip->mixbuff[0] += (Bit16s)((accm * chip->channel[ii].chl / 65535) & chip->channel[ii].cha); } for (ii = 15; ii < 18; ii++) @@ -1097,7 +1126,7 @@ void OPL3_Generate(opl3_chip *chip, Bit16s *buf) { accm += *chip->channel[ii].out[jj]; } - chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); + chip->mixbuff[1] += (Bit16s)((accm * chip->channel[ii].chr / 65535) & chip->channel[ii].chb); } for (ii = 33; ii < 36; ii++) @@ -1229,6 +1258,8 @@ void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) chip->channel[channum].chtype = ch_2op; chip->channel[channum].cha = 0xffff; chip->channel[channum].chb = 0xffff; + chip->channel[channum].chl = 46340; + chip->channel[channum].chr = 46340; chip->channel[channum].ch_num = channum; OPL3_ChannelSetupAlg(&chip->channel[channum]); } @@ -1238,6 +1269,19 @@ void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) chip->vibshift = 1; } +static void OPL3_ChannelWritePan(opl3_channel *channel, Bit8u data) +{ + channel->chl = panlawtable[data & 0x7F]; + channel->chr = panlawtable[0x7F - (data & 0x7F)]; +} + +void OPL3_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v) +{ + Bit8u high = (reg >> 8) & 0x01; + Bit8u regm = reg & 0xff; + OPL3_ChannelWritePan(&chip->channel[9 * high + (regm & 0x0f)], v); +} + void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) { Bit8u high = (reg >> 8) & 0x01; diff --git a/src/sound/adlmidi/chips/nuked/nukedopl3.h b/src/sound/adlmidi/chips/nuked/nukedopl3.h index d57cf5fb5..268e8de64 100644 --- a/src/sound/adlmidi/chips/nuked/nukedopl3.h +++ b/src/sound/adlmidi/chips/nuked/nukedopl3.h @@ -1,16 +1,19 @@ /* * Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Nuked OPL3 emulator. * Thanks: @@ -98,6 +101,7 @@ struct _opl3_channel { Bit8u alg; Bit8u ksv; Bit16u cha, chb; + Bit16u chl, chr; Bit8u ch_num; }; @@ -150,6 +154,7 @@ void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf); void OPL3_Reset(opl3_chip *chip, Bit32u samplerate); void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v); void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); void OPL3_GenerateStreamMix(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); diff --git a/src/sound/adlmidi/chips/nuked/nukedopl3_174.c b/src/sound/adlmidi/chips/nuked/nukedopl3_174.c index 99eab16dc..8f818d4ee 100644 --- a/src/sound/adlmidi/chips/nuked/nukedopl3_174.c +++ b/src/sound/adlmidi/chips/nuked/nukedopl3_174.c @@ -229,6 +229,32 @@ static const Bit8u ch_slot[18] = { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 }; +/* + * Pan law table + */ + +static const Bit16u panlawtable[] = +{ + 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, + 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, + 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, + 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, + 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, + 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, + 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, + 50433, 49912, 49383, 48846, 48302, 47750, 47191, + 46340, /* Center left */ + 46340, /* Center right */ + 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, + 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, + 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, + 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, + 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, + 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, + 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, + 4858, 4050, 3240, 2431, 1620, 810, 0 +}; + /* * Envelope generator */ @@ -1082,7 +1108,7 @@ void OPL3v17_Generate(opl3_chip *chip, Bit16s *buf) { accm += *chip->channel[ii].out[jj]; } - chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); + chip->mixbuff[0] += (Bit16s)((accm * chip->channel[ii].chl / 65535) & chip->channel[ii].cha); } for (ii = 15; ii < 18; ii++) @@ -1121,7 +1147,7 @@ void OPL3v17_Generate(opl3_chip *chip, Bit16s *buf) { accm += *chip->channel[ii].out[jj]; } - chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); + chip->mixbuff[1] += (Bit16s)((accm * chip->channel[ii].chr / 65535) & chip->channel[ii].chb); } for (ii = 33; ii < 36; ii++) @@ -1220,8 +1246,10 @@ void OPL3v17_Reset(opl3_chip *chip, Bit32u samplerate) chip->channel[channum].out[2] = &chip->zeromod; chip->channel[channum].out[3] = &chip->zeromod; chip->channel[channum].chtype = ch_2op; - chip->channel[channum].cha = ~0; - chip->channel[channum].chb = ~0; + chip->channel[channum].cha = 0xffff; + chip->channel[channum].chb = 0xffff; + chip->channel[channum].chl = 46340; + chip->channel[channum].chr = 46340; OPL3_ChannelSetupAlg(&chip->channel[channum]); } chip->noise = 0x306600; @@ -1230,6 +1258,19 @@ void OPL3v17_Reset(opl3_chip *chip, Bit32u samplerate) chip->vibshift = 1; } +static void OPL3v17_ChannelWritePan(opl3_channel *channel, Bit8u data) +{ + channel->chl = panlawtable[data & 0x7F]; + channel->chr = panlawtable[0x7F - (data & 0x7F)]; +} + +void OPL3v17_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v) +{ + Bit8u high = (reg >> 8) & 0x01; + Bit8u regm = reg & 0xff; + OPL3v17_ChannelWritePan(&chip->channel[9 * high + (regm & 0x0f)], v); +} + void OPL3v17_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) { Bit8u high = (reg >> 8) & 0x01; diff --git a/src/sound/adlmidi/chips/nuked/nukedopl3_174.h b/src/sound/adlmidi/chips/nuked/nukedopl3_174.h index 240802f4f..cd185620c 100644 --- a/src/sound/adlmidi/chips/nuked/nukedopl3_174.h +++ b/src/sound/adlmidi/chips/nuked/nukedopl3_174.h @@ -103,6 +103,7 @@ struct _opl3_channel { Bit8u alg; Bit8u ksv; Bit16u cha, chb; + Bit16u chl, chr; }; typedef struct _opl3_writebuf { @@ -142,6 +143,7 @@ struct _opl3_chip { void OPL3v17_Generate(opl3_chip *chip, Bit16s *buf); void OPL3v17_GenerateResampled(opl3_chip *chip, Bit16s *buf); void OPL3v17_Reset(opl3_chip *chip, Bit32u samplerate); +void OPL3v17_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v); void OPL3v17_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); void OPL3v17_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); void OPL3v17_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); diff --git a/src/sound/adlmidi/chips/nuked_opl3.cpp b/src/sound/adlmidi/chips/nuked_opl3.cpp index 48e5c1736..bbf4a2518 100644 --- a/src/sound/adlmidi/chips/nuked_opl3.cpp +++ b/src/sound/adlmidi/chips/nuked_opl3.cpp @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPL3 (YMF262) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include "nuked_opl3.h" #include "nuked/nukedopl3.h" #include @@ -37,6 +57,12 @@ void NukedOPL3::writeReg(uint16_t addr, uint8_t data) OPL3_WriteRegBuffered(chip_r, addr, data); } +void NukedOPL3::writePan(uint16_t addr, uint8_t data) +{ + opl3_chip *chip_r = reinterpret_cast(m_chip); + OPL3_WritePan(chip_r, addr, data); +} + void NukedOPL3::nativeGenerate(int16_t *frame) { opl3_chip *chip_r = reinterpret_cast(m_chip); diff --git a/src/sound/adlmidi/chips/nuked_opl3.h b/src/sound/adlmidi/chips/nuked_opl3.h index 1b34e9ab5..33baf549a 100644 --- a/src/sound/adlmidi/chips/nuked_opl3.h +++ b/src/sound/adlmidi/chips/nuked_opl3.h @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPL3 (YMF262) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef NUKED_OPL3_H #define NUKED_OPL3_H @@ -14,6 +34,7 @@ public: void setRate(uint32_t rate) override; void reset() override; void writeReg(uint16_t addr, uint8_t data) override; + void writePan(uint16_t addr, uint8_t data) override; void nativePreGenerate() override {} void nativePostGenerate() override {} void nativeGenerate(int16_t *frame) override; diff --git a/src/sound/adlmidi/chips/nuked_opl3_v174.cpp b/src/sound/adlmidi/chips/nuked_opl3_v174.cpp index e24b2e706..6bb06c280 100644 --- a/src/sound/adlmidi/chips/nuked_opl3_v174.cpp +++ b/src/sound/adlmidi/chips/nuked_opl3_v174.cpp @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPL3 (YMF262) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include "nuked_opl3_v174.h" #include "nuked/nukedopl3_174.h" #include @@ -37,6 +57,12 @@ void NukedOPL3v174::writeReg(uint16_t addr, uint8_t data) OPL3v17_WriteReg(chip_r, addr, data); } +void NukedOPL3v174::writePan(uint16_t addr, uint8_t data) +{ + opl3_chip *chip_r = reinterpret_cast(m_chip); + OPL3v17_WritePan(chip_r, addr, data); +} + void NukedOPL3v174::nativeGenerate(int16_t *frame) { opl3_chip *chip_r = reinterpret_cast(m_chip); diff --git a/src/sound/adlmidi/chips/nuked_opl3_v174.h b/src/sound/adlmidi/chips/nuked_opl3_v174.h index f14221fe0..9eaeb192a 100644 --- a/src/sound/adlmidi/chips/nuked_opl3_v174.h +++ b/src/sound/adlmidi/chips/nuked_opl3_v174.h @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPL3 (YMF262) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef NUKED_OPL3174_H #define NUKED_OPL3174_H @@ -14,6 +34,7 @@ public: void setRate(uint32_t rate) override; void reset() override; void writeReg(uint16_t addr, uint8_t data) override; + void writePan(uint16_t addr, uint8_t data) override; void nativePreGenerate() override {} void nativePostGenerate() override {} void nativeGenerate(int16_t *frame) override; diff --git a/src/sound/adlmidi/chips/opl_chip_base.h b/src/sound/adlmidi/chips/opl_chip_base.h index 879d6dad8..723bbc9bc 100644 --- a/src/sound/adlmidi/chips/opl_chip_base.h +++ b/src/sound/adlmidi/chips/opl_chip_base.h @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef ONP_CHIP_BASE_H #define ONP_CHIP_BASE_H @@ -43,6 +61,9 @@ public: virtual void reset() = 0; virtual void writeReg(uint16_t addr, uint8_t data) = 0; + // extended + virtual void writePan(uint16_t addr, uint8_t data) { (void)addr; (void)data; } + virtual void nativePreGenerate() = 0; virtual void nativePostGenerate() = 0; virtual void nativeGenerate(int16_t *frame) = 0; diff --git a/src/sound/adlmidi/chips/opl_chip_base.tcc b/src/sound/adlmidi/chips/opl_chip_base.tcc index 48ad103fa..a64aa7c19 100644 --- a/src/sound/adlmidi/chips/opl_chip_base.tcc +++ b/src/sound/adlmidi/chips/opl_chip_base.tcc @@ -236,8 +236,8 @@ void OPLChipBaseT::resampledGenerate(int32_t *output) rsm->out_count = 1; rsm->out_data = f_out; } - output[0] = std::lround(f_out[0]); - output[1] = std::lround(f_out[1]); + output[0] = static_cast(std::lround(f_out[0])); + output[1] = static_cast(std::lround(f_out[1])); } #else template diff --git a/src/sound/adlmidi/file_reader.hpp b/src/sound/adlmidi/file_reader.hpp new file mode 100644 index 000000000..7d13262a1 --- /dev/null +++ b/src/sound/adlmidi/file_reader.hpp @@ -0,0 +1,300 @@ +/* + * FileAndMemoryReader - a tiny helper to utify file reading from a disk and memory block + * + * Copyright (c) 2015-2018 Vitaly Novichkov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef FILE_AND_MEM_READER_HHHH +#define FILE_AND_MEM_READER_HHHH + +#include // std::string +#include // std::fopen, std::fread, std::fseek, std::ftell, std::fclose, std::feof +#include // uint*_t +#include // size_t and friends +#ifdef _WIN32 +#define NOMINMAX 1 +#include // std::strlen +#include // MultiByteToWideChar +#endif + +/** + * @brief A little class gives able to read filedata from disk and also from a memory segment + */ +class FileAndMemReader +{ + //! Currently loaded filename (empty for a memory blocks) + std::string m_file_name; + //! File reader descriptor + std::FILE *m_fp; + + //! Memory pointer descriptor + const void *m_mp; + //! Size of memory block + size_t m_mp_size; + //! Cursor position in the memory block + size_t m_mp_tell; + +public: + /** + * @brief Relation direction + */ + enum relTo + { + //! At begin position + SET = SEEK_SET, + //! At current position + CUR = SEEK_CUR, + //! At end position + END = SEEK_END + }; + + /** + * @brief C.O.: It's a constructor! + */ + FileAndMemReader() : + m_fp(NULL), + m_mp(NULL), + m_mp_size(0), + m_mp_tell(0) + {} + + /** + * @brief C.O.: It's a destructor! + */ + ~FileAndMemReader() + { + close(); + } + + /** + * @brief Open file from a disk + * @param path Path to the file in UTF-8 (even on Windows!) + */ + void openFile(const char *path) + { + if(m_fp) + this->close();//Close previously opened file first! +#if !defined(_WIN32) || defined(__WATCOMC__) + m_fp = std::fopen(path, "rb"); +#else + wchar_t widePath[MAX_PATH]; + int size = MultiByteToWideChar(CP_UTF8, 0, path, static_cast(std::strlen(path)), widePath, MAX_PATH); + widePath[size] = '\0'; + m_fp = _wfopen(widePath, L"rb"); +#endif + m_file_name = path; + m_mp = NULL; + m_mp_size = 0; + m_mp_tell = 0; + } + + /** + * @brief Open file from memory block + * @param mem Pointer to the memory block + * @param lenght Size of given block + */ + void openData(const void *mem, size_t lenght) + { + if(m_fp) + this->close();//Close previously opened file first! + m_fp = NULL; + m_mp = mem; + m_mp_size = lenght; + m_mp_tell = 0; + } + + /** + * @brief Seek to given position + * @param pos Offset or position + * @param rel_to Relation (at begin, at current, or at end) + */ + void seek(long pos, int rel_to) + { + if(!this->isValid()) + return; + + if(m_fp)//If a file + { + std::fseek(m_fp, pos, rel_to); + } + else//If a memory block + { + switch(rel_to) + { + case SET: + m_mp_tell = static_cast(pos); + break; + + case END: + m_mp_tell = m_mp_size - static_cast(pos); + break; + + case CUR: + m_mp_tell = m_mp_tell + static_cast(pos); + break; + } + + if(m_mp_tell > m_mp_size) + m_mp_tell = m_mp_size; + } + } + + /** + * @brief Seek to given position (unsigned integer 64 as relation. Negative values not supported) + * @param pos Offset or position + * @param rel_to Relation (at begin, at current, or at end) + */ + inline void seeku(uint64_t pos, int rel_to) + { + this->seek(static_cast(pos), rel_to); + } + + /** + * @brief Read the buffer from a file + * @param buf Pointer to the destination memory block + * @param num Number of elements + * @param size Size of one element + * @return Size + */ + size_t read(void *buf, size_t num, size_t size) + { + if(!this->isValid()) + return 0; + if(m_fp) + return std::fread(buf, num, size, m_fp); + else + { + size_t pos = 0; + size_t maxSize = static_cast(size * num); + + while((pos < maxSize) && (m_mp_tell < m_mp_size)) + { + reinterpret_cast(buf)[pos] = reinterpret_cast(m_mp)[m_mp_tell]; + m_mp_tell++; + pos++; + } + + return pos / num; + } + } + + /** + * @brief Get one byte and seek forward + * @return Readed byte or EOF (a.k.a. -1) + */ + int getc() + { + if(!this->isValid()) + return -1; + if(m_fp)//If a file + { + return std::getc(m_fp); + } + else //If a memory block + { + if(m_mp_tell >= m_mp_size) + return -1; + int x = reinterpret_cast(m_mp)[m_mp_tell]; + m_mp_tell++; + return x; + } + } + + /** + * @brief Returns current offset of cursor in a file + * @return Offset position + */ + size_t tell() + { + if(!this->isValid()) + return 0; + if(m_fp)//If a file + return static_cast(std::ftell(m_fp)); + else//If a memory block + return m_mp_tell; + } + + /** + * @brief Close the file + */ + void close() + { + if(m_fp) + std::fclose(m_fp); + + m_fp = NULL; + m_mp = NULL; + m_mp_size = 0; + m_mp_tell = 0; + } + + /** + * @brief Is file instance valid + * @return true if vaild + */ + bool isValid() + { + return (m_fp) || (m_mp); + } + + /** + * @brief Is End Of File? + * @return true if end of file was reached + */ + bool eof() + { + if(!this->isValid()) + return true; + if(m_fp) + return (std::feof(m_fp) != 0); + else + return m_mp_tell >= m_mp_size; + } + + /** + * @brief Get a current file name + * @return File name of currently loaded file + */ + const std::string &fileName() + { + return m_file_name; + } + + /** + * @brief Retrieve file size + * @return Size of file in bytes + */ + size_t fileSize() + { + if(!this->isValid()) + return 0; + if(!m_fp) + return m_mp_size; //Size of memory block is well known + size_t old_pos = this->tell(); + seek(0l, FileAndMemReader::END); + size_t file_size = this->tell(); + seek(static_cast(old_pos), FileAndMemReader::SET); + return file_size; + } +}; + +#endif /* FILE_AND_MEM_READER_HHHH */ diff --git a/src/sound/adlmidi/fraction.hpp b/src/sound/adlmidi/fraction.hpp deleted file mode 100644 index 1c0a38dde..000000000 --- a/src/sound/adlmidi/fraction.hpp +++ /dev/null @@ -1,215 +0,0 @@ -#ifndef bqw_fraction_h -#define bqw_fraction_h - -#include -#include - - -/* Fraction number handling. - * Copyright (C) 1992,2001 Bisqwit (http://iki.fi/bisqwit/) - */ - -template -class fraction -{ - inttype num1, num2; - typedef fraction self; - void Optim(); - - #if 1 - inline void Debug(char, const self &) { } - #else - inline void Debug(char op, const self &b) - { - cerr << nom() << '/' << denom() << ' ' << op - << ' ' << b.nom() << '/' << denom() - << ":\n"; - } - #endif -public: - void set(inttype n, inttype d) { num1=n; num2=d; Optim(); } - - fraction() : num1(0), num2(1) { } - fraction(inttype value) : num1(value), num2(1) { } - fraction(inttype n, inttype d) : num1(n), num2(d) { } - fraction(int value) : num1(value), num2(1) { } - template - explicit fraction(const floattype value) { operator= (value); } - inline double value() const {return nom() / (double)denom(); } - inline long double valuel() const {return nom() / (long double)denom(); } - self &operator+= (const inttype &value) { num1+=value*denom(); Optim(); return *this; } - self &operator-= (const inttype &value) { num1-=value*denom(); Optim(); return *this; } - self &operator*= (const inttype &value) { num1*=value; Optim(); return *this; } - self &operator/= (const inttype &value) { num2*=value; Optim(); return *this; } - self &operator+= (const self &b); - self &operator-= (const self &b); - self &operator*= (const self &b) { Debug('*',b);num1*=b.nom(); num2*=b.denom(); Optim(); return *this; } - self &operator/= (const self &b) { Debug('/',b);num1*=b.denom(); num2*=b.nom(); Optim(); return *this; } - self operator- () const { return self(-num1, num2); } - -#define fraction_blah_func(op1, op2) \ - self operator op1 (const self &b) const { self tmp(*this); tmp op2 b; return tmp; } - - fraction_blah_func( +, += ) - fraction_blah_func( -, -= ) - fraction_blah_func( /, /= ) - fraction_blah_func( *, *= ) - -#undef fraction_blah_func -#define fraction_blah_func(op) \ - bool operator op(const self &b) const { return value() op b.value(); } \ - bool operator op(inttype b) const { return value() op b; } - - fraction_blah_func( < ) - fraction_blah_func( > ) - fraction_blah_func( <= ) - fraction_blah_func( >= ) - -#undef fraction_blah_func - - const inttype &nom() const { return num1; } - const inttype &denom() const { return num2; } - inline bool operator == (inttype b) const { return denom() == 1 && nom() == b; } - inline bool operator != (inttype b) const { return denom() != 1 || nom() != b; } - inline bool operator == (const self &b) const { return denom()==b.denom() && nom()==b.nom(); } - inline bool operator != (const self &b) const { return denom()!=b.denom() || nom()!=b.nom(); } - //operator bool () const { return nom() != 0; } - inline bool negative() const { return (nom() < 0) ^ (denom() < 0); } - - self &operator= (const inttype value) { num2=1; num1=value; return *this; } - //self &operator= (int value) { num2=1; num1=value; return *this; } - - self &operator= (double orig) { return *this = (long double)orig; } - self &operator= (long double orig); -}; - -#ifdef _MSC_VER -#pragma warning(disable:4146) -#endif - -template -void fraction::Optim() -{ - /* Euclidean algorithm */ - inttype n1, n2, nn1, nn2; - - nn1 = std::numeric_limits::is_signed ? (num1 >= 0 ? num1 : -num1) : num1; - nn2 = std::numeric_limits::is_signed ? (num2 >= 0 ? num2 : -num2) : num2; - - if(nn1 < nn2) - n1 = num1, n2 = num2; - else - n1 = num2, n2 = num1; - - if(!num1) { num2 = 1; return; } - for(;;) - { - //fprintf(stderr, "%d/%d: n1=%d,n2=%d\n", nom(),denom(),n1,n2); - inttype tmp = n2 % n1; - if(!tmp)break; - n2 = n1; - n1 = tmp; - } - num1 /= n1; - num2 /= n1; - //fprintf(stderr, "result: %d/%d\n\n", nom(), denom()); -} - -#ifdef _MSC_VER -#pragma warning(default:4146) -#endif - -template -inline const fraction abs(const fraction &f) -{ - return fraction(abs(f.nom()), abs(f.denom())); -} - -#define fraction_blah_func(op) \ - template \ - fraction operator op \ - (const inttype bla, const fraction &b) \ - { return fraction (bla) op b; } -fraction_blah_func( + ) -fraction_blah_func( - ) -fraction_blah_func( * ) -fraction_blah_func( / ) -#undef fraction_blah_func - -#define fraction_blah_func(op1, op2) \ - template \ - fraction &fraction::operator op2 (const fraction &b) \ - { \ - inttype newnom = nom()*b.denom() op1 denom()*b.nom(); \ - num2 *= b.denom(); \ - num1 = newnom; \ - Optim(); \ - return *this; \ - } -fraction_blah_func( +, += ) -fraction_blah_func( -, -= ) -#undef fraction_blah_func - -template -fraction &fraction::operator= (long double orig) -{ - if(orig == 0.0) - { - set(0, 0); - return *this; - } - - inttype cf[25]; - for(int maxdepth=1; maxdepth<25; ++maxdepth) - { - inttype u,v; - long double virhe, a=orig; - int i, viim; - - for(i = 0; i < maxdepth; ++i) - { - cf[i] = (inttype)a; - if(cf[i]-1 > cf[i])break; - a = 1.0 / (a - cf[i]); - } - - for(viim=i-1; i < maxdepth; ++i) - cf[i] = 0; - - u = cf[viim]; - v = 1; - for(i = viim-1; i >= 0; --i) - { - inttype w = cf[i] * u + v; - v = u; - u = w; - } - - virhe = (orig - (u / (long double)v)) / orig; - - set(u, v); - //if(verbose > 4) - // cerr << "Guess: " << *this << " - error = " << virhe*100 << "%\n"; - - if(virhe < 1e-8 && virhe > -1e-8)break; - } - - //if(verbose > 4) - //{ - // cerr << "Fraction=" << orig << ": " << *this << endl; - //} - - return *this; -} - - -/* -template -ostream &operator << (ostream &dest, const fraction &m) -{ - if(m.denom() == (inttype)1) return dest << m.nom(); - return dest << m.nom() << '/' << m.denom(); -} -*/ - -#endif diff --git a/src/sound/adlmidi/wopl/wopl_file.c b/src/sound/adlmidi/wopl/wopl_file.c index 25b75be53..f018cbce9 100644 --- a/src/sound/adlmidi/wopl/wopl_file.c +++ b/src/sound/adlmidi/wopl/wopl_file.c @@ -353,6 +353,8 @@ int WOPL_LoadInstFromMem(WOPIFile *file, void *mem, size_t length) GO_FORWARD(2); } + file->version = version; + {/* is drum flag */ if(length < 1) return WOPL_ERR_UNEXPECTED_ENDING; @@ -434,11 +436,13 @@ size_t WOPL_CalculateInstFileSize(WOPIFile *file, uint16_t version) * is percussive instrument */ - if(version >= 3) - ins_size = WOPL_INST_SIZE_V3; + if(version > 2) + /* Skip sounding delays are not part of single-instrument file + * two sizes of uint16_t will be subtracted */ + ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2); else ins_size = WOPL_INST_SIZE_V2; - final_size += ins_size * 128; + final_size += ins_size; return final_size; } diff --git a/src/sound/adlmidi/wopl/wopl_file.h b/src/sound/adlmidi/wopl/wopl_file.h index 0e3884243..fa270b6f8 100644 --- a/src/sound/adlmidi/wopl/wopl_file.h +++ b/src/sound/adlmidi/wopl/wopl_file.h @@ -71,13 +71,13 @@ typedef enum WOPL_InstrumentFlags WOPL_Ins_IsBlank = 0x04, /* RythmMode flags mask */ - WOPL_RythmModeMask = 0x38, + WOPL_RhythmModeMask = 0x38, /* Mask of the flags range */ WOPL_Ins_ALL_MASK = 0x07 } WOPL_InstrumentFlags; -typedef enum WOPL_RythmMode +typedef enum WOPL_RhythmMode { /* RythmMode: BassDrum */ WOPL_RM_BassDrum = 0x08, @@ -86,10 +86,13 @@ typedef enum WOPL_RythmMode /* RythmMode: TomTom */ WOPL_RM_TomTom = 0x18, /* RythmMode: Cymbell */ - WOPL_RM_Cymball = 0x20, + WOPL_RM_Cymbal = 0x20, /* RythmMode: HiHat */ WOPL_RM_HiHat = 0x28 -} WOPL_RythmMode; +} WOPL_RhythmMode; + +/* DEPRECATED: It has typo. Don't use it! */ +typedef WOPL_RhythmMode WOPL_RythmMode; /* Error codes */ typedef enum WOPL_ErrorCodes diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index cccc12241..c638afbe7 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -331,6 +331,9 @@ protected: void HandleEvent(int status, int parm1, int parm2); void HandleLongEvent(const uint8_t *data, int len); void ComputeOutput(float *buffer, int len); + +private: + int LoadCustomBank(const char *bankfile); }; @@ -341,14 +344,17 @@ public: OPNMIDIDevice(const char *args); ~OPNMIDIDevice(); + int Open(MidiCallback, void *userdata); int GetDeviceType() const override { return MDEV_OPN; } protected: - void HandleEvent(int status, int parm1, int parm2); void HandleLongEvent(const uint8_t *data, int len); void ComputeOutput(float *buffer, int len); + +private: + int LoadCustomBank(const char *bankfile); }; diff --git a/src/sound/i_soundfont.cpp b/src/sound/i_soundfont.cpp index eb2027215..a591eac97 100644 --- a/src/sound/i_soundfont.cpp +++ b/src/sound/i_soundfont.cpp @@ -302,6 +302,16 @@ void FSoundFontManager::ProcessOneFile(const FString &fn) FSoundFontInfo sft = { fb, fbe, fn, SF_SF2 }; soundfonts.Push(sft); } + if (!memcmp(head, "WOPL3-BANK\0", 11)) + { + FSoundFontInfo sft = { fb, fbe, fn, SF_WOPL }; + soundfonts.Push(sft); + } + if (!memcmp(head, "WOPN2-BANK\0", 11) || !memcmp(head, "WOPN2-B2NK\0", 11)) + { + FSoundFontInfo sft = { fb, fbe, fn, SF_WOPN }; + soundfonts.Push(sft); + } else if (!memcmp(head, "PK", 2)) { auto zip = FResourceFile::OpenResourceFile(fn, true); @@ -333,19 +343,18 @@ void FSoundFontManager::CollectSoundfonts() { findstate_t c_file; void *file; - - + if (GameConfig != NULL && GameConfig->SetSection ("SoundfontSearch.Directories")) { const char *key; const char *value; - + while (GameConfig->NextInSection (key, value)) { if (stricmp (key, "Path") == 0) { FString dir; - + dir = NicePath(value); FixPathSeperator(dir); if (dir.IsNotEmpty()) diff --git a/src/sound/i_soundfont.h b/src/sound/i_soundfont.h index 5ef60102c..681558a86 100644 --- a/src/sound/i_soundfont.h +++ b/src/sound/i_soundfont.h @@ -7,7 +7,9 @@ enum { SF_SF2 = 1, - SF_GUS = 2 + SF_GUS = 2, + SF_WOPL = 4, + SF_WOPN = 8 }; struct FSoundFontInfo diff --git a/src/sound/mididevices/music_adlmidi_mididevice.cpp b/src/sound/mididevices/music_adlmidi_mididevice.cpp index 7cece2ec6..061f6abab 100644 --- a/src/sound/mididevices/music_adlmidi_mididevice.cpp +++ b/src/sound/mididevices/music_adlmidi_mididevice.cpp @@ -36,6 +36,7 @@ #include "i_musicinterns.h" #include "adlmidi/adlmidi.h" +#include "i_soundfont.h" enum { @@ -72,6 +73,15 @@ CUSTOM_CVAR(Bool, adl_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } } +CUSTOM_CVAR(Bool, adl_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (currSong != nullptr && currSong->GetDeviceType() == MDEV_ADL) + { + MIDIDeviceChanged(-1, true); + } +} + + CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (currSong != nullptr && currSong->GetDeviceType() == MDEV_ADL) @@ -118,18 +128,11 @@ ADLMIDIDevice::ADLMIDIDevice(const char *args) { adl_switchEmulator(Renderer, (int)adl_emulator_id); adl_setRunAtPcmRate(Renderer, (int)adl_run_at_pcm_rate); -// todo: Implement handling of external or in-resources WOPL bank files and load -/* - if(adl_use_custom_bank) - { - adl_openBankFile(Renderer, (char*)adl_bank_file); - adl_openBankData(Renderer, (char*)adl_bank, (unsigned long)size); - } - else -*/ + if(!LoadCustomBank(adl_custom_bank)) adl_setBank(Renderer, (int)adl_bank); adl_setNumChips(Renderer, (int)adl_chips_count); adl_setVolumeRangeModel(Renderer, (int)adl_volume_model); + adl_setSoftPanEnabled(Renderer, (int)adl_fullpan); } } @@ -148,6 +151,27 @@ ADLMIDIDevice::~ADLMIDIDevice() } } +//========================================================================== +// +// ADLMIDIDevice :: LoadCustomBank +// +// Loads a custom WOPL bank for libADLMIDI. Returns 1 when bank has been +// loaded, otherwise, returns 0 when custom banks are disabled or failed +// +//========================================================================== + +int ADLMIDIDevice::LoadCustomBank(const char *bankfile) +{ + if(!adl_use_custom_bank) + return 0; + auto info = sfmanager.FindSoundFont(bankfile, SF_WOPL); + if(info == nullptr) + return 0; + bankfile = info->mFilename.GetChars(); + return (adl_openBankFile(Renderer, bankfile) == 0); +} + + //========================================================================== // // ADLMIDIDevice :: Open diff --git a/src/sound/mididevices/music_opnmidi_mididevice.cpp b/src/sound/mididevices/music_opnmidi_mididevice.cpp index de27644c3..d9f5d6124 100644 --- a/src/sound/mididevices/music_opnmidi_mididevice.cpp +++ b/src/sound/mididevices/music_opnmidi_mididevice.cpp @@ -38,6 +38,7 @@ #include "w_wad.h" #include "i_system.h" #include "opnmidi/opnmidi.h" +#include "i_soundfont.h" enum { @@ -74,6 +75,14 @@ CUSTOM_CVAR(Bool, opn_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } } +CUSTOM_CVAR(Bool, opn_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPN) + { + MIDIDeviceChanged(-1, true); + } +} + CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPN) @@ -102,25 +111,21 @@ OPNMIDIDevice::OPNMIDIDevice(const char *args) Renderer = opn2_init(44100); // todo: make it configurable if (Renderer != nullptr) { + if (!LoadCustomBank(opn_custom_bank)) + { + int lump = Wads.CheckNumForFullName("xg.wopn"); + if (lump < 0) + { + I_Error("No OPN bank found"); + } + FMemLump data = Wads.ReadLump(lump); + opn2_openBankData(Renderer, data.GetMem(), (long)data.GetSize()); + } + opn2_switchEmulator(Renderer, (int)opn_emulator_id); opn2_setRunAtPcmRate(Renderer, (int)opn_run_at_pcm_rate); -// todo: Implement handling of external or in-resources WOPN bank files and load -/* - if(opn_use_custom_bank) - { - opn2_openBankFile(Renderer, (char*)opn_bank_file); - opn2_openBankData(Renderer, (char*)opn_bank, (long)size); - } - else - */ - int lump = Wads.CheckNumForFullName("xg.wopn"); - if (lump < 0) - { - I_Error("No OPN bank found"); - } - FMemLump data = Wads.ReadLump(lump); - opn2_openBankData(Renderer, data.GetMem(), (long)data.GetSize()); opn2_setNumChips(Renderer, opn_chips_count); + opn2_setSoftPanEnabled(Renderer, (int)opn_fullpan); } } @@ -139,6 +144,27 @@ OPNMIDIDevice::~OPNMIDIDevice() } } +//========================================================================== +// +// OPNMIDIDevice :: LoadCustomBank +// +// Loads a custom WOPN bank for libOPNMIDI. Returns 1 when bank has been +// loaded, otherwise, returns 0 when custom banks are disabled or failed +// +//========================================================================== + + +int OPNMIDIDevice::LoadCustomBank(const char *bankfile) +{ + if(!opn_use_custom_bank) + return 0; + auto info = sfmanager.FindSoundFont(bankfile, SF_WOPN); + if(info == nullptr) + return 0; + bankfile = info->mFilename.GetChars(); + return (opn2_openBankFile(Renderer, bankfile) == 0); +} + //========================================================================== // // OPNMIDIDevice :: Open diff --git a/src/sound/opnmidi/chips/gens/Ym2612_Emu.cpp b/src/sound/opnmidi/chips/gens/Ym2612_Emu.cpp index 18285bf84..9bdc0d1d4 100644 --- a/src/sound/opnmidi/chips/gens/Ym2612_Emu.cpp +++ b/src/sound/opnmidi/chips/gens/Ym2612_Emu.cpp @@ -1,4 +1,4 @@ -// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/ +// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/ // Based on Gens 2.10 ym2612.c @@ -96,6 +96,8 @@ struct channel_t int KC[4]; // Key Code = valeur fonction de la frequence (voir KSR pour les slots, KSR = KC >> KSR_S) slot_t SLOT[4]; // four slot.operators = les 4 slots de la voie int FFlag; // Frequency step recalculation flag + int PANVolumeL; // Left PCM output channel volume + int PANVolumeR; // Right PCM output channel volume }; struct state_t @@ -253,6 +255,32 @@ static const unsigned char LFO_FMS_TAB [8] = LFO_FMS_BASE * 12, LFO_FMS_BASE * 24 }; + +/* + * Pan law table + */ +static const unsigned short panlawtable[] = +{ + 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, + 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, + 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, + 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, + 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, + 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, + 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, + 50433, 49912, 49383, 48846, 48302, 47750, 47191, + 46340, /* Center left */ + 46340, /* Center right */ + 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, + 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, + 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, + 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, + 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, + 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, + 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, + 4858, 4050, 3240, 2431, 1620, 810, 0 +}; + inline void YM2612_Special_Update() { } struct Ym2612_Impl @@ -273,6 +301,7 @@ struct Ym2612_Impl void reset(); void write0( int addr, int data ); void write1( int addr, int data ); + void write_pan(int channel, int data ); void run_timer( int ); void run( int pair_count, Ym2612_Emu::sample_t* ); }; @@ -880,6 +909,12 @@ inline void Ym2612_Impl::write1( int opn_addr, int data ) } } +void Ym2612_Impl::write_pan( int channel, int data ) +{ + YM2612.CHANNEL[channel].PANVolumeL = panlawtable[data & 0x7F]; + YM2612.CHANNEL[channel].PANVolumeR = panlawtable[0x7F - (data & 0x7F)]; +} + void Ym2612_Emu::reset() { impl->reset(); @@ -910,6 +945,9 @@ void Ym2612_Impl::reset() ch.FMS = 0; ch.AMS = 0; + ch.PANVolumeL = 46340; + ch.PANVolumeR = 46340; + for ( int j = 0 ;j < 4 ; j++ ) { ch.S0_OUT [j] = 0; @@ -959,6 +997,11 @@ void Ym2612_Emu::write1( int addr, int data ) impl->write1( addr, data ); } +void Ym2612_Emu::write_pan(int channel, int data) +{ + impl->write_pan( channel, data ); +} + void Ym2612_Emu::mute_voices( int mask ) { impl->mute_mask = mask; } static void update_envelope_( slot_t* sl ) @@ -1166,10 +1209,10 @@ void ym2612_update_chan::func( tables_t& g, channel_t& ch, in1 += (ch.SLOT [S1].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); in2 += (ch.SLOT [S2].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); in3 += (ch.SLOT [S3].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); - - int t0 = buf [0] + (CH_OUTd & ch.LEFT); - int t1 = buf [1] + (CH_OUTd & ch.RIGHT); - + + int t0 = buf [0] + ((CH_OUTd * ch.PANVolumeL / 65535) & ch.LEFT); + int t1 = buf [1] + ((CH_OUTd * ch.PANVolumeR / 65535) & ch.RIGHT); + update_envelope( ch.SLOT [0] ); update_envelope( ch.SLOT [1] ); update_envelope( ch.SLOT [2] ); diff --git a/src/sound/opnmidi/chips/gens/Ym2612_Emu.h b/src/sound/opnmidi/chips/gens/Ym2612_Emu.h index efce1e2d1..f483d1bb3 100644 --- a/src/sound/opnmidi/chips/gens/Ym2612_Emu.h +++ b/src/sound/opnmidi/chips/gens/Ym2612_Emu.h @@ -29,6 +29,9 @@ public: // Write addr to register 2 then data to register 3 void write1( int addr, int data ); + // Write pan level channel data + void write_pan( int channel, int data ); + // Run and add pair_count samples into current output buffer contents typedef short sample_t; enum { out_chan_count = 2 }; // stereo diff --git a/src/sound/opnmidi/chips/gens_opn2.cpp b/src/sound/opnmidi/chips/gens_opn2.cpp index 3e8977c77..a43e57ebc 100644 --- a/src/sound/opnmidi/chips/gens_opn2.cpp +++ b/src/sound/opnmidi/chips/gens_opn2.cpp @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPN2 (YM2612) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include "gens_opn2.h" #include @@ -40,6 +60,11 @@ void GensOPN2::writeReg(uint32_t port, uint16_t addr, uint8_t data) } } +void GensOPN2::writePan(uint16_t chan, uint8_t data) +{ + chip->write_pan(static_cast(chan), static_cast(data)); +} + void GensOPN2::nativeGenerateN(int16_t *output, size_t frames) { std::memset(output, 0, frames * sizeof(int16_t) * 2); diff --git a/src/sound/opnmidi/chips/gens_opn2.h b/src/sound/opnmidi/chips/gens_opn2.h index 158ffc69b..240a6208c 100644 --- a/src/sound/opnmidi/chips/gens_opn2.h +++ b/src/sound/opnmidi/chips/gens_opn2.h @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPN2 (YM2612) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef GENS_OPN2_H #define GENS_OPN2_H @@ -15,6 +35,7 @@ public: void setRate(uint32_t rate, uint32_t clock) override; void reset() override; void writeReg(uint32_t port, uint16_t addr, uint8_t data) override; + void writePan(uint16_t chan, uint8_t data) override; void nativePreGenerate() override {} void nativePostGenerate() override {} void nativeGenerateN(int16_t *output, size_t frames) override; diff --git a/src/sound/opnmidi/chips/mame/mame_ym2612fm.c b/src/sound/opnmidi/chips/mame/mame_ym2612fm.c index 0628a878a..46d1b012f 100644 --- a/src/sound/opnmidi/chips/mame/mame_ym2612fm.c +++ b/src/sound/opnmidi/chips/mame/mame_ym2612fm.c @@ -136,6 +136,7 @@ #include #include /* for memset */ #include /* for NULL */ +#include #include #include "mamedef.h" #include "mame_ym2612fm.h" @@ -543,6 +544,33 @@ static FILE *sample[1]; #endif +/* + * Pan law table + */ + +static const UINT16 panlawtable[] = +{ + 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, + 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, + 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, + 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, + 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, + 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, + 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, + 50433, 49912, 49383, 48846, 48302, 47750, 47191, + 46340, /* Center left */ + 46340, /* Center right */ + 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, + 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, + 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, + 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, + 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, + 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, + 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, + 4858, 4050, 3240, 2431, 1620, 810, 0 +}; + + /* struct describing a single operator (SLOT) */ typedef struct { @@ -608,6 +636,9 @@ typedef struct UINT8 kcode; /* key code: */ UINT32 block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */ UINT8 Muted; + + INT32 pan_volume_l; + INT32 pan_volume_r; } FM_CH; @@ -2457,34 +2488,40 @@ void ym2612_generate_one_native(void *chip, FMSAMPLE buffer[]) if (out_fm[5] > 8192) out_fm[5] = 8192; else if (out_fm[5] < -8192) out_fm[5] = -8192; +#define PANLAW_L(ch, chpan) (((out_fm[ch]>>0) * cch[ch].pan_volume_l / 65535) & OPN->pan[chpan]); +#define PANLAW_R(ch, chpan) (((out_fm[ch]>>0) * cch[ch].pan_volume_r / 65535) & OPN->pan[chpan]); + /* 6-channels mixing */ - lt = ((out_fm[0]>>0) & OPN->pan[0]); - rt = ((out_fm[0]>>0) & OPN->pan[1]); - lt += ((out_fm[1]>>0) & OPN->pan[2]); - rt += ((out_fm[1]>>0) & OPN->pan[3]); - lt += ((out_fm[2]>>0) & OPN->pan[4]); - rt += ((out_fm[2]>>0) & OPN->pan[5]); - lt += ((out_fm[3]>>0) & OPN->pan[6]); - rt += ((out_fm[3]>>0) & OPN->pan[7]); + lt = PANLAW_L(0, 0); + rt = PANLAW_R(0, 1); + lt += PANLAW_L(1, 2); + rt += PANLAW_R(1, 3); + lt += PANLAW_L(2, 4); + rt += PANLAW_R(2, 5); + lt += PANLAW_L(3, 6); + rt += PANLAW_R(3, 7); if (! F2612->dac_test) { - lt += ((out_fm[4]>>0) & OPN->pan[8]); - rt += ((out_fm[4]>>0) & OPN->pan[9]); + lt += PANLAW_L(4, 8); + rt += PANLAW_R(4, 9); } else { lt += dacout; - lt += dacout; + rt += dacout; } - lt += ((out_fm[5]>>0) & OPN->pan[10]); - rt += ((out_fm[5]>>0) & OPN->pan[11]); + lt += PANLAW_L(5, 10); + rt += PANLAW_R(5, 11); + +#undef PANLAW_L +#undef PANLAW_R /* Limit( lt, MAXOUT, MINOUT ); */ /* Limit( rt, MAXOUT, MINOUT ); */ - #ifdef SAVE_SAMPLE - SAVE_ALL_CHANNELS - #endif +#ifdef SAVE_SAMPLE + SAVE_ALL_CHANNELS +#endif /* buffering */ if (F2612->WaveOutMode & 0x01) @@ -2587,6 +2624,7 @@ void * ym2612_init(void *param, int clock, int rate, FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler) { YM2612 *F2612; + int i = 0; if (clock <= 0 || rate <= 0) return NULL; /* Forbid zero clock and sample rate */ @@ -2624,6 +2662,13 @@ void * ym2612_init(void *param, int clock, int rate, F2612->WaveOutMode = 0x01; else F2612->WaveOutMode = 0x03; + + for (i = 0; i < 6; i++) + { + F2612->CH[i].pan_volume_l = 46340; + F2612->CH[i].pan_volume_r = 46340; + } + /*hFile = fopen("YM2612.log", "wt"); fprintf(hFile, "Clock: %d, Sample Rate: %d\n", clock, rate); fprintf(hFile, "Sample\tCh 0\tCh 1\tCh 2\tCh 3\tCh 4\tCh 5\n"); @@ -2786,6 +2831,14 @@ int ym2612_write(void *chip, int a, UINT8 v) return F2612->OPN.ST.irq; } +void ym2612_write_pan(void *chip, int c, unsigned char v) +{ + YM2612 *F2612 = (YM2612 *)chip; + assert((c >= 0) && (c < 6)); + F2612->CH[c].pan_volume_l = panlawtable[v & 0x7F]; + F2612->CH[c].pan_volume_r = panlawtable[0x7F - (v & 0x7F)]; +} + UINT8 ym2612_read(void *chip,int a) { YM2612 *F2612 = (YM2612 *)chip; diff --git a/src/sound/opnmidi/chips/mame/mame_ym2612fm.h b/src/sound/opnmidi/chips/mame/mame_ym2612fm.h index de05236ef..5b209bb53 100644 --- a/src/sound/opnmidi/chips/mame/mame_ym2612fm.h +++ b/src/sound/opnmidi/chips/mame/mame_ym2612fm.h @@ -148,8 +148,9 @@ void ym2612_generate_one_native(void *chip, FMSAMPLE buffer[2]); /* void ym2612_post_generate(void *chip, int length); */ -int ym2612_write(void *chip, int a,unsigned char v); -unsigned char ym2612_read(void *chip,int a); +int ym2612_write(void *chip, int a, unsigned char v); +void ym2612_write_pan(void *chip, int c, unsigned char v); +unsigned char ym2612_read(void *chip, int a); int ym2612_timer_over(void *chip, int c ); void ym2612_postload(void *chip); diff --git a/src/sound/opnmidi/chips/mame_opn2.cpp b/src/sound/opnmidi/chips/mame_opn2.cpp index e9533131f..611988931 100644 --- a/src/sound/opnmidi/chips/mame_opn2.cpp +++ b/src/sound/opnmidi/chips/mame_opn2.cpp @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPN2 (YM2612) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include "mame_opn2.h" #include "mame/mame_ym2612fm.h" #include @@ -36,6 +56,11 @@ void MameOPN2::writeReg(uint32_t port, uint16_t addr, uint8_t data) ym2612_write(chip, 1 + (int)(port) * 2, data); } +void MameOPN2::writePan(uint16_t chan, uint8_t data) +{ + ym2612_write_pan(chip, (int)chan, data); +} + void MameOPN2::nativePreGenerate() { void *chip = this->chip; diff --git a/src/sound/opnmidi/chips/mame_opn2.h b/src/sound/opnmidi/chips/mame_opn2.h index 832602476..2fe5e0374 100644 --- a/src/sound/opnmidi/chips/mame_opn2.h +++ b/src/sound/opnmidi/chips/mame_opn2.h @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPN2 (YM2612) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef MAME_OPN2_H #define MAME_OPN2_H @@ -14,6 +34,7 @@ public: void setRate(uint32_t rate, uint32_t clock) override; void reset() override; void writeReg(uint32_t port, uint16_t addr, uint8_t data) override; + void writePan(uint16_t chan, uint8_t data) override; void nativePreGenerate() override; void nativePostGenerate() override {} void nativeGenerate(int16_t *frame) override; diff --git a/src/sound/opnmidi/chips/nuked/ym3438.c b/src/sound/opnmidi/chips/nuked/ym3438.c index 019ca4cde..8c170b768 100644 --- a/src/sound/opnmidi/chips/nuked/ym3438.c +++ b/src/sound/opnmidi/chips/nuked/ym3438.c @@ -1,19 +1,19 @@ /* * Copyright (C) 2017 Alexey Khokholov (Nuke.YKT) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * Nuked OPN2(Yamaha YM3438) emulator. @@ -216,6 +216,32 @@ static const Bit32u fm_algorithm[4][6][8] = { } }; +/* + * Pan law table + */ + +static const Bit16u panlawtable[] = +{ + 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, + 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, + 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, + 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, + 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, + 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, + 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, + 50433, 49912, 49383, 48846, 48302, 47750, 47191, + 46340, /* Center left */ + 46340, /* Center right */ + 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, + 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, + 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, + 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, + 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, + 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, + 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, + 4858, 4050, 3240, 2431, 1620, 810, 0 +}; + static Bit32u chip_type = ym3438_type_discrete; void OPN2_DoIO(ym3438_t *chip) @@ -1204,6 +1230,8 @@ void OPN2_Reset(ym3438_t *chip, Bit32u rate, Bit32u clock) { chip->pan_l[i] = 1; chip->pan_r[i] = 1; + chip->pan_volume_l[i] = 46340; + chip->pan_volume_r[i] = 46340; } if (rate != 0) @@ -1426,6 +1454,13 @@ Bit8u OPN2_Read(ym3438_t *chip, Bit32u port) return 0; } + +void OPN2_WritePan(ym3438_t *chip, Bit32u channel, Bit8u data) +{ + chip->pan_volume_l[channel] = panlawtable[data & 0x7F]; + chip->pan_volume_r[channel] = panlawtable[0x7F - (data & 0x7F)]; +} + void OPN2_WriteBuffered(ym3438_t *chip, Bit32u port, Bit8u data) { Bit64u time1, time2; @@ -1466,6 +1501,7 @@ void OPN2_Generate(ym3438_t *chip, Bit16s *buf) Bit32u i; Bit16s buffer[2]; Bit32u mute; + Bit32s channel = -1; buf[0] = 0; buf[1] = 0; @@ -1476,21 +1512,27 @@ void OPN2_Generate(ym3438_t *chip, Bit16s *buf) { case 0: /* Ch 2 */ mute = chip->mute[1]; + channel = 1; break; case 1: /* Ch 6, DAC */ mute = chip->mute[5 + chip->dacen]; + channel = 5; break; case 2: /* Ch 4 */ mute = chip->mute[3]; + channel = 3; break; case 3: /* Ch 1 */ mute = chip->mute[0]; + channel = 0; break; case 4: /* Ch 5 */ mute = chip->mute[4]; + channel = 4; break; case 5: /* Ch 3 */ mute = chip->mute[2]; + channel = 2; break; default: mute = 0; @@ -1499,6 +1541,11 @@ void OPN2_Generate(ym3438_t *chip, Bit16s *buf) OPN2_Clock(chip, buffer); if (!mute) { + if (channel >= 0) + { + buffer[0] = buffer[0] * chip->pan_volume_l[channel] / 65535; + buffer[1] = buffer[1] * chip->pan_volume_r[channel] / 65535; + } buf[0] += buffer[0]; buf[1] += buffer[1]; } diff --git a/src/sound/opnmidi/chips/nuked/ym3438.h b/src/sound/opnmidi/chips/nuked/ym3438.h index c277f087b..2a3b5bf3d 100644 --- a/src/sound/opnmidi/chips/nuked/ym3438.h +++ b/src/sound/opnmidi/chips/nuked/ym3438.h @@ -1,19 +1,19 @@ /* * Copyright (C) 2017 Alexey Khokholov (Nuke.YKT) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * Nuked OPN2(Yamaha YM3438) emulator. @@ -213,6 +213,9 @@ typedef struct Bit32s oldsamples[2]; Bit32s samples[2]; + Bit32u pan_volume_l[6]; + Bit32u pan_volume_r[6]; + Bit64u writebuf_samplecnt; Bit32u writebuf_cur; Bit32u writebuf_last; @@ -231,6 +234,7 @@ Bit32u OPN2_ReadIRQPin(ym3438_t *chip); Bit8u OPN2_Read(ym3438_t *chip, Bit32u port); /*EXTRA*/ +void OPN2_WritePan(ym3438_t *chip, Bit32u channel, Bit8u data); void OPN2_WriteBuffered(ym3438_t *chip, Bit32u port, Bit8u data); void OPN2_Generate(ym3438_t *chip, Bit16s *buf); void OPN2_GenerateResampled(ym3438_t *chip, Bit16s *buf); diff --git a/src/sound/opnmidi/chips/nuked_opn2.cpp b/src/sound/opnmidi/chips/nuked_opn2.cpp index e452ccf0f..2c2ec46f1 100644 --- a/src/sound/opnmidi/chips/nuked_opn2.cpp +++ b/src/sound/opnmidi/chips/nuked_opn2.cpp @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPN2 (YM2612) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include "nuked_opn2.h" #include "nuked/ym3438.h" #include @@ -37,6 +57,12 @@ void NukedOPN2::writeReg(uint32_t port, uint16_t addr, uint8_t data) //qDebug() << QString("%1: 0x%2 => 0x%3").arg(port).arg(addr, 2, 16, QChar('0')).arg(data, 2, 16, QChar('0')); } +void NukedOPN2::writePan(uint16_t chan, uint8_t data) +{ + ym3438_t *chip_r = reinterpret_cast(chip); + OPN2_WritePan(chip_r, (Bit32u)chan, data); +} + void NukedOPN2::nativeGenerate(int16_t *frame) { ym3438_t *chip_r = reinterpret_cast(chip); diff --git a/src/sound/opnmidi/chips/nuked_opn2.h b/src/sound/opnmidi/chips/nuked_opn2.h index 9eb239f48..ff5d25581 100644 --- a/src/sound/opnmidi/chips/nuked_opn2.h +++ b/src/sound/opnmidi/chips/nuked_opn2.h @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPN2 (YM2612) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef NUKED_OPN2_H #define NUKED_OPN2_H @@ -14,6 +34,7 @@ public: void setRate(uint32_t rate, uint32_t clock) override; void reset() override; void writeReg(uint32_t port, uint16_t addr, uint8_t data) override; + void writePan(uint16_t chan, uint8_t data) override; void nativePreGenerate() override {} void nativePostGenerate() override {} void nativeGenerate(int16_t *frame) override; diff --git a/src/sound/opnmidi/chips/opn_chip_base.h b/src/sound/opnmidi/chips/opn_chip_base.h index 5c532c920..fb02c32a4 100644 --- a/src/sound/opnmidi/chips/opn_chip_base.h +++ b/src/sound/opnmidi/chips/opn_chip_base.h @@ -1,3 +1,23 @@ +/* + * Interfaces over Yamaha OPN2 (YM2612) chip emulators + * + * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef ONP_CHIP_BASE_H #define ONP_CHIP_BASE_H @@ -13,25 +33,40 @@ class VResampler; #endif +#if defined(OPNMIDI_AUDIO_TICK_HANDLER) +extern void opn2_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate); +#endif + class OPNChipBase { public: enum { nativeRate = 53267 }; protected: + uint32_t m_id; uint32_t m_rate; uint32_t m_clock; public: OPNChipBase(); virtual ~OPNChipBase(); + uint32_t chipId() const { return m_id; } + void setChipId(uint32_t id) { m_id = id; } + virtual bool canRunAtPcmRate() const = 0; virtual bool isRunningAtPcmRate() const = 0; virtual bool setRunningAtPcmRate(bool r) = 0; +#if defined(OPNMIDI_AUDIO_TICK_HANDLER) + virtual void setAudioTickHandlerInstance(void *instance) = 0; +#endif virtual void setRate(uint32_t rate, uint32_t clock) = 0; + virtual uint32_t effectiveRate() const = 0; virtual void reset() = 0; virtual void writeReg(uint32_t port, uint16_t addr, uint8_t data) = 0; + // extended + virtual void writePan(uint16_t addr, uint8_t data) { (void)addr; (void)data; } + virtual void nativePreGenerate() = 0; virtual void nativePostGenerate() = 0; virtual void nativeGenerate(int16_t *frame) = 0; @@ -58,8 +93,12 @@ public: bool isRunningAtPcmRate() const override; bool setRunningAtPcmRate(bool r) override; +#if defined(OPNMIDI_AUDIO_TICK_HANDLER) + void setAudioTickHandlerInstance(void *instance); +#endif virtual void setRate(uint32_t rate, uint32_t clock) override; + uint32_t effectiveRate() const override; virtual void reset() override; void generate(int16_t *output, size_t frames) override; void generateAndMix(int16_t *output, size_t frames) override; @@ -67,6 +106,10 @@ public: void generateAndMix32(int32_t *output, size_t frames) override; private: bool m_runningAtPcmRate; +#if defined(OPNMIDI_AUDIO_TICK_HANDLER) + void *m_audioTickHandlerInstance; +#endif + void nativeTick(int16_t *frame); void setupResampler(uint32_t rate); void resetResampler(); void resampledGenerate(int32_t *output); diff --git a/src/sound/opnmidi/chips/opn_chip_base.tcc b/src/sound/opnmidi/chips/opn_chip_base.tcc index 4915e802d..1302ea5bf 100644 --- a/src/sound/opnmidi/chips/opn_chip_base.tcc +++ b/src/sound/opnmidi/chips/opn_chip_base.tcc @@ -20,6 +20,7 @@ /* OPNChipBase */ inline OPNChipBase::OPNChipBase() : + m_id(0), m_rate(44100), m_clock(7670454) { @@ -35,6 +36,10 @@ template OPNChipBaseT::OPNChipBaseT() : OPNChipBase(), m_runningAtPcmRate(false) +#if defined(OPNMIDI_AUDIO_TICK_HANDLER) + , + m_audioTickHandlerInstance(NULL) +#endif { #if defined(OPNMIDI_ENABLE_HQ_RESAMPLER) m_resampler = new VResampler; @@ -69,6 +74,14 @@ bool OPNChipBaseT::setRunningAtPcmRate(bool r) return true; } +#if defined(OPNMIDI_AUDIO_TICK_HANDLER) +template +void OPNChipBaseT::setAudioTickHandlerInstance(void *instance) +{ + m_audioTickHandlerInstance = instance; +} +#endif + template void OPNChipBaseT::setRate(uint32_t rate, uint32_t clock) { @@ -81,6 +94,12 @@ void OPNChipBaseT::setRate(uint32_t rate, uint32_t clock) resetResampler(); } +template +uint32_t OPNChipBaseT::effectiveRate() const +{ + return m_runningAtPcmRate ? m_rate : (uint32_t)nativeRate; +} + template void OPNChipBaseT::reset() { @@ -152,6 +171,15 @@ void OPNChipBaseT::generateAndMix32(int32_t *output, size_t frames) static_cast(this)->nativePostGenerate(); } +template +void OPNChipBaseT::nativeTick(int16_t *frame) +{ +#if defined(OPNMIDI_AUDIO_TICK_HANDLER) + opn2_audioTickHandler(m_audioTickHandlerInstance, m_id, effectiveRate()); +#endif + static_cast(this)->nativeGenerate(frame); +} + template void OPNChipBaseT::setupResampler(uint32_t rate) { @@ -184,7 +212,7 @@ void OPNChipBaseT::resampledGenerate(int32_t *output) if(UNLIKELY(m_runningAtPcmRate)) { int16_t in[2]; - static_cast(this)->nativeGenerate(in); + static_cast(this)->nativeTick(in); output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate; output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate; return; @@ -202,7 +230,7 @@ void OPNChipBaseT::resampledGenerate(int32_t *output) while(rsm->process(), rsm->out_count != 0) { int16_t in[2]; - static_cast(this)->nativeGenerate(in); + static_cast(this)->nativeTick(in); f_in[0] = scale * (float)in[0]; f_in[1] = scale * (float)in[1]; rsm->inp_count = 1; @@ -210,8 +238,8 @@ void OPNChipBaseT::resampledGenerate(int32_t *output) rsm->out_count = 1; rsm->out_data = f_out; } - output[0] = std::lround(f_out[0]); - output[1] = std::lround(f_out[1]); + output[0] = static_cast(std::lround(f_out[0])); + output[1] = static_cast(std::lround(f_out[1])); } #else template @@ -220,7 +248,7 @@ void OPNChipBaseT::resampledGenerate(int32_t *output) if(UNLIKELY(m_runningAtPcmRate)) { int16_t in[2]; - static_cast(this)->nativeGenerate(in); + static_cast(this)->nativeTick(in); output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate; output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate; return; @@ -233,7 +261,7 @@ void OPNChipBaseT::resampledGenerate(int32_t *output) m_oldsamples[0] = m_samples[0]; m_oldsamples[1] = m_samples[1]; int16_t buffer[2]; - static_cast(this)->nativeGenerate(buffer); + static_cast(this)->nativeTick(buffer); m_samples[0] = buffer[0] * T::resamplerPreAmplify; m_samples[1] = buffer[1] * T::resamplerPreAmplify; samplecnt -= rateratio; diff --git a/src/sound/opnmidi/file_reader.hpp b/src/sound/opnmidi/file_reader.hpp new file mode 100644 index 000000000..7d13262a1 --- /dev/null +++ b/src/sound/opnmidi/file_reader.hpp @@ -0,0 +1,300 @@ +/* + * FileAndMemoryReader - a tiny helper to utify file reading from a disk and memory block + * + * Copyright (c) 2015-2018 Vitaly Novichkov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#ifndef FILE_AND_MEM_READER_HHHH +#define FILE_AND_MEM_READER_HHHH + +#include // std::string +#include // std::fopen, std::fread, std::fseek, std::ftell, std::fclose, std::feof +#include // uint*_t +#include // size_t and friends +#ifdef _WIN32 +#define NOMINMAX 1 +#include // std::strlen +#include // MultiByteToWideChar +#endif + +/** + * @brief A little class gives able to read filedata from disk and also from a memory segment + */ +class FileAndMemReader +{ + //! Currently loaded filename (empty for a memory blocks) + std::string m_file_name; + //! File reader descriptor + std::FILE *m_fp; + + //! Memory pointer descriptor + const void *m_mp; + //! Size of memory block + size_t m_mp_size; + //! Cursor position in the memory block + size_t m_mp_tell; + +public: + /** + * @brief Relation direction + */ + enum relTo + { + //! At begin position + SET = SEEK_SET, + //! At current position + CUR = SEEK_CUR, + //! At end position + END = SEEK_END + }; + + /** + * @brief C.O.: It's a constructor! + */ + FileAndMemReader() : + m_fp(NULL), + m_mp(NULL), + m_mp_size(0), + m_mp_tell(0) + {} + + /** + * @brief C.O.: It's a destructor! + */ + ~FileAndMemReader() + { + close(); + } + + /** + * @brief Open file from a disk + * @param path Path to the file in UTF-8 (even on Windows!) + */ + void openFile(const char *path) + { + if(m_fp) + this->close();//Close previously opened file first! +#if !defined(_WIN32) || defined(__WATCOMC__) + m_fp = std::fopen(path, "rb"); +#else + wchar_t widePath[MAX_PATH]; + int size = MultiByteToWideChar(CP_UTF8, 0, path, static_cast(std::strlen(path)), widePath, MAX_PATH); + widePath[size] = '\0'; + m_fp = _wfopen(widePath, L"rb"); +#endif + m_file_name = path; + m_mp = NULL; + m_mp_size = 0; + m_mp_tell = 0; + } + + /** + * @brief Open file from memory block + * @param mem Pointer to the memory block + * @param lenght Size of given block + */ + void openData(const void *mem, size_t lenght) + { + if(m_fp) + this->close();//Close previously opened file first! + m_fp = NULL; + m_mp = mem; + m_mp_size = lenght; + m_mp_tell = 0; + } + + /** + * @brief Seek to given position + * @param pos Offset or position + * @param rel_to Relation (at begin, at current, or at end) + */ + void seek(long pos, int rel_to) + { + if(!this->isValid()) + return; + + if(m_fp)//If a file + { + std::fseek(m_fp, pos, rel_to); + } + else//If a memory block + { + switch(rel_to) + { + case SET: + m_mp_tell = static_cast(pos); + break; + + case END: + m_mp_tell = m_mp_size - static_cast(pos); + break; + + case CUR: + m_mp_tell = m_mp_tell + static_cast(pos); + break; + } + + if(m_mp_tell > m_mp_size) + m_mp_tell = m_mp_size; + } + } + + /** + * @brief Seek to given position (unsigned integer 64 as relation. Negative values not supported) + * @param pos Offset or position + * @param rel_to Relation (at begin, at current, or at end) + */ + inline void seeku(uint64_t pos, int rel_to) + { + this->seek(static_cast(pos), rel_to); + } + + /** + * @brief Read the buffer from a file + * @param buf Pointer to the destination memory block + * @param num Number of elements + * @param size Size of one element + * @return Size + */ + size_t read(void *buf, size_t num, size_t size) + { + if(!this->isValid()) + return 0; + if(m_fp) + return std::fread(buf, num, size, m_fp); + else + { + size_t pos = 0; + size_t maxSize = static_cast(size * num); + + while((pos < maxSize) && (m_mp_tell < m_mp_size)) + { + reinterpret_cast(buf)[pos] = reinterpret_cast(m_mp)[m_mp_tell]; + m_mp_tell++; + pos++; + } + + return pos / num; + } + } + + /** + * @brief Get one byte and seek forward + * @return Readed byte or EOF (a.k.a. -1) + */ + int getc() + { + if(!this->isValid()) + return -1; + if(m_fp)//If a file + { + return std::getc(m_fp); + } + else //If a memory block + { + if(m_mp_tell >= m_mp_size) + return -1; + int x = reinterpret_cast(m_mp)[m_mp_tell]; + m_mp_tell++; + return x; + } + } + + /** + * @brief Returns current offset of cursor in a file + * @return Offset position + */ + size_t tell() + { + if(!this->isValid()) + return 0; + if(m_fp)//If a file + return static_cast(std::ftell(m_fp)); + else//If a memory block + return m_mp_tell; + } + + /** + * @brief Close the file + */ + void close() + { + if(m_fp) + std::fclose(m_fp); + + m_fp = NULL; + m_mp = NULL; + m_mp_size = 0; + m_mp_tell = 0; + } + + /** + * @brief Is file instance valid + * @return true if vaild + */ + bool isValid() + { + return (m_fp) || (m_mp); + } + + /** + * @brief Is End Of File? + * @return true if end of file was reached + */ + bool eof() + { + if(!this->isValid()) + return true; + if(m_fp) + return (std::feof(m_fp) != 0); + else + return m_mp_tell >= m_mp_size; + } + + /** + * @brief Get a current file name + * @return File name of currently loaded file + */ + const std::string &fileName() + { + return m_file_name; + } + + /** + * @brief Retrieve file size + * @return Size of file in bytes + */ + size_t fileSize() + { + if(!this->isValid()) + return 0; + if(!m_fp) + return m_mp_size; //Size of memory block is well known + size_t old_pos = this->tell(); + seek(0l, FileAndMemReader::END); + size_t file_size = this->tell(); + seek(static_cast(old_pos), FileAndMemReader::SET); + return file_size; + } +}; + +#endif /* FILE_AND_MEM_READER_HHHH */ diff --git a/src/sound/opnmidi/fraction.hpp b/src/sound/opnmidi/fraction.hpp deleted file mode 100644 index 7aab95bd2..000000000 --- a/src/sound/opnmidi/fraction.hpp +++ /dev/null @@ -1,214 +0,0 @@ -#ifndef bqw_fraction_h -#define bqw_fraction_h - -#include -#include - -/* Fraction number handling. - * Copyright (C) 1992,2001 Bisqwit (http://iki.fi/bisqwit/) - */ - -template -class fraction -{ - inttype num1, num2; - typedef fraction self; - void Optim(); - - #if 1 - inline void Debug(char, const self &) { } - #else - inline void Debug(char op, const self &b) - { - cerr << nom() << '/' << denom() << ' ' << op - << ' ' << b.nom() << '/' << denom() - << ":\n"; - } - #endif -public: - void set(inttype n, inttype d) { num1=n; num2=d; Optim(); } - - fraction() : num1(0), num2(1) { } - fraction(inttype value) : num1(value), num2(1) { } - fraction(inttype n, inttype d) : num1(n), num2(d) { } - fraction(int value) : num1(value), num2(1) { } - template - explicit fraction(const floattype value) { operator= (value); } - inline double value() const {return nom() / (double)denom(); } - inline long double valuel() const {return nom() / (long double)denom(); } - self &operator+= (const inttype &value) { num1+=value*denom(); Optim(); return *this; } - self &operator-= (const inttype &value) { num1-=value*denom(); Optim(); return *this; } - self &operator*= (const inttype &value) { num1*=value; Optim(); return *this; } - self &operator/= (const inttype &value) { num2*=value; Optim(); return *this; } - self &operator+= (const self &b); - self &operator-= (const self &b); - self &operator*= (const self &b) { Debug('*',b);num1*=b.nom(); num2*=b.denom(); Optim(); return *this; } - self &operator/= (const self &b) { Debug('/',b);num1*=b.denom(); num2*=b.nom(); Optim(); return *this; } - self operator- () const { return self(-num1, num2); } - -#define fraction_blah_func(op1, op2) \ - self operator op1 (const self &b) const { self tmp(*this); tmp op2 b; return tmp; } - - fraction_blah_func( +, += ) - fraction_blah_func( -, -= ) - fraction_blah_func( /, /= ) - fraction_blah_func( *, *= ) - -#undef fraction_blah_func -#define fraction_blah_func(op) \ - bool operator op(const self &b) const { return value() op b.value(); } \ - bool operator op(inttype b) const { return value() op b; } - - fraction_blah_func( < ) - fraction_blah_func( > ) - fraction_blah_func( <= ) - fraction_blah_func( >= ) - -#undef fraction_blah_func - - const inttype &nom() const { return num1; } - const inttype &denom() const { return num2; } - inline bool operator == (inttype b) const { return denom() == 1 && nom() == b; } - inline bool operator != (inttype b) const { return denom() != 1 || nom() != b; } - inline bool operator == (const self &b) const { return denom()==b.denom() && nom()==b.nom(); } - inline bool operator != (const self &b) const { return denom()!=b.denom() || nom()!=b.nom(); } - //operator bool () const { return nom() != 0; } - inline bool negative() const { return (nom() < 0) ^ (denom() < 0); } - - self &operator= (const inttype value) { num2=1; num1=value; return *this; } - //self &operator= (int value) { num2=1; num1=value; return *this; } - - self &operator= (double orig) { return *this = (long double)orig; } - self &operator= (long double orig); -}; - -#ifdef _MSC_VER -#pragma warning(disable:4146) -#endif - -template -void fraction::Optim() -{ - /* Euclidean algorithm */ - inttype n1, n2, nn1, nn2; - - nn1 = std::numeric_limits::is_signed ? (num1 >= 0 ? num1 : -num1) : num1; - nn2 = std::numeric_limits::is_signed ? (num2 >= 0 ? num2 : -num2) : num2; - - if(nn1 < nn2) - n1 = num1, n2 = num2; - else - n1 = num2, n2 = num1; - - if(!num1) { num2 = 1; return; } - for(;;) - { - //fprintf(stderr, "%d/%d: n1=%d,n2=%d\n", nom(),denom(),n1,n2); - inttype tmp = n2 % n1; - if(!tmp)break; - n2 = n1; - n1 = tmp; - } - num1 /= n1; - num2 /= n1; - //fprintf(stderr, "result: %d/%d\n\n", nom(), denom()); -} - -#ifdef _MSC_VER -#pragma warning(default:4146) -#endif - -template -inline const fraction abs(const fraction &f) -{ - return fraction(abs(f.nom()), abs(f.denom())); -} - -#define fraction_blah_func(op) \ - template \ - fraction operator op \ - (const inttype bla, const fraction &b) \ - { return fraction (bla) op b; } -fraction_blah_func( + ) -fraction_blah_func( - ) -fraction_blah_func( * ) -fraction_blah_func( / ) -#undef fraction_blah_func - -#define fraction_blah_func(op1, op2) \ - template \ - fraction &fraction::operator op2 (const fraction &b) \ - { \ - inttype newnom = nom()*b.denom() op1 denom()*b.nom(); \ - num2 *= b.denom(); \ - num1 = newnom; \ - Optim(); \ - return *this; \ - } -fraction_blah_func( +, += ) -fraction_blah_func( -, -= ) -#undef fraction_blah_func - -template -fraction &fraction::operator= (long double orig) -{ - if(orig == 0.0) - { - set(0, 0); - return *this; - } - - inttype cf[25]; - for(int maxdepth=1; maxdepth<25; ++maxdepth) - { - inttype u,v; - long double virhe, a=orig; - int i, viim; - - for(i = 0; i < maxdepth; ++i) - { - cf[i] = (inttype)a; - if(cf[i]-1 > cf[i])break; - a = 1.0 / (a - cf[i]); - } - - for(viim=i-1; i < maxdepth; ++i) - cf[i] = 0; - - u = cf[viim]; - v = 1; - for(i = viim-1; i >= 0; --i) - { - inttype w = cf[i] * u + v; - v = u; - u = w; - } - - virhe = (orig - (u / (long double)v)) / orig; - - set(u, v); - //if(verbose > 4) - // cerr << "Guess: " << *this << " - error = " << virhe*100 << "%\n"; - - if(virhe < 1e-8 && virhe > -1e-8)break; - } - - //if(verbose > 4) - //{ - // cerr << "Fraction=" << orig << ": " << *this << endl; - //} - - return *this; -} - - -/* -template -ostream &operator << (ostream &dest, const fraction &m) -{ - if(m.denom() == (inttype)1) return dest << m.nom(); - return dest << m.nom() << '/' << m.denom(); -} -*/ - -#endif diff --git a/src/sound/opnmidi/opnbank.h b/src/sound/opnmidi/opnbank.h index 521616ae1..0e005a3db 100644 --- a/src/sound/opnmidi/opnbank.h +++ b/src/sound/opnmidi/opnbank.h @@ -110,6 +110,7 @@ struct opnInstMeta2 uint16_t ms_sound_kon; // Number of milliseconds it produces sound; uint16_t ms_sound_koff; double fine_tune; + int8_t midi_velocity_offset; #if 0 opnInstMeta2() {} explicit opnInstMeta2(const opnInstMeta &d); @@ -120,6 +121,16 @@ OPNDATA_BYTE_COMPARABLE(struct opnInstMeta2) #undef OPNDATA_BYTE_COMPARABLE #pragma pack(pop) +/** + * @brief Bank global setup + */ +struct OpnBankSetup +{ + int volumeModel; + int lfoEnable; + int lfoFrequency; +}; + #if 0 /** * @brief Conversion of storage formats @@ -127,11 +138,21 @@ OPNDATA_BYTE_COMPARABLE(struct opnInstMeta2) inline opnInstMeta2::opnInstMeta2(const opnInstMeta &d) : tone(d.tone), flags(d.flags), ms_sound_kon(d.ms_sound_kon), ms_sound_koff(d.ms_sound_koff), - fine_tune(d.fine_tune) + fine_tune(d.fine_tune), midi_velocity_offset(d.midi_velocity_offset) { opn[0] = ::opn[d.opnno1]; opn[1] = ::opn[d.opnno2]; } #endif +/** + * @brief Convert external instrument to internal instrument + */ +void cvt_OPNI_to_FMIns(opnInstMeta2 &dst, const struct OPN2_Instrument &src); + +/** + * @brief Convert internal instrument to external instrument + */ +void cvt_FMIns_to_OPNI(struct OPN2_Instrument &dst, const opnInstMeta2 &src); + #endif // OPNMIDI_OPNBANK_H diff --git a/src/sound/opnmidi/opnmidi.cpp b/src/sound/opnmidi/opnmidi.cpp index eab98eee7..2f35e2a05 100644 --- a/src/sound/opnmidi/opnmidi.cpp +++ b/src/sound/opnmidi/opnmidi.cpp @@ -23,8 +23,9 @@ #include "opnmidi_private.hpp" -#define MaxCards 100 -#define MaxCards_STR "100" +/* Unify MIDI player casting and interface between ADLMIDI and OPNMIDI */ +#define GET_MIDI_PLAYER(device) reinterpret_cast((device)->opn2_midiPlayer) +typedef OPNMIDIplay MidiPlayer; static OPN2_Version opn2_version = { OPNMIDI_VERSION_MAJOR, @@ -51,7 +52,7 @@ OPNMIDI_EXPORT struct OPN2_MIDIPlayer *opn2_init(long sample_rate) return NULL; } - OPNMIDIplay *player = new OPNMIDIplay(static_cast(sample_rate)); + OPNMIDIplay *player = new(std::nothrow) OPNMIDIplay(static_cast(sample_rate)); if(!player) { free(midi_device); @@ -59,44 +60,208 @@ OPNMIDI_EXPORT struct OPN2_MIDIPlayer *opn2_init(long sample_rate) return NULL; } midi_device->opn2_midiPlayer = player; - opn2RefreshNumCards(midi_device); return midi_device; } +OPNMIDI_EXPORT int opn2_setDeviceIdentifier(OPN2_MIDIPlayer *device, unsigned id) +{ + if(!device || id > 0x0f) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->setDeviceId(static_cast(id)); + return 0; +} + OPNMIDI_EXPORT int opn2_setNumChips(OPN2_MIDIPlayer *device, int numCards) { if(device == NULL) return -2; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - play->m_setup.NumCards = static_cast(numCards); - if(play->m_setup.NumCards < 1 || play->m_setup.NumCards > MaxCards) + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.numChips = static_cast(numCards); + if(play->m_setup.numChips < 1 || play->m_setup.numChips > OPN_MAX_CHIPS) { - play->setErrorString("number of chips may only be 1.." MaxCards_STR ".\n"); + play->setErrorString("number of chips may only be 1.." OPN_MAX_CHIPS_STR ".\n"); return -1; } - play->opn.NumCards = play->m_setup.NumCards; - opn2_reset(device); + if(!play->m_synth.setupLocked()) + { + play->m_synth.m_numChips = play->m_setup.numChips; + play->partialReset(); + } - return opn2RefreshNumCards(device); + return 0; } OPNMIDI_EXPORT int opn2_getNumChips(struct OPN2_MIDIPlayer *device) { if(device == NULL) return -2; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - return (int)play->m_setup.NumCards; - return -2; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return (int)play->m_setup.numChips; +} + +OPNMIDI_EXPORT int opn2_getNumChipsObtained(struct OPN2_MIDIPlayer *device) +{ + if(device == NULL) + return -2; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return (int)play->m_synth.m_numChips; +} + + +OPNMIDI_EXPORT int opn2_reserveBanks(OPN2_MIDIPlayer *device, unsigned banks) +{ + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPN2::BankMap &map = play->m_synth.m_insBanks; + map.reserve(banks); + return (int)map.capacity(); +} + +OPNMIDI_EXPORT int opn2_getBank(OPN2_MIDIPlayer *device, const OPN2_BankId *idp, int flags, OPN2_Bank *bank) +{ + if(!device || !idp || !bank) + return -1; + + OPN2_BankId id = *idp; + if(id.lsb > 127 || id.msb > 127 || id.percussive > 1) + return -1; + size_t idnumber = ((id.msb << 8) | id.lsb | (id.percussive ? size_t(OPN2::PercussionTag) : 0)); + + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPN2::BankMap &map = play->m_synth.m_insBanks; + + OPN2::BankMap::iterator it; + if(!(flags & OPNMIDI_Bank_Create)) + { + it = map.find(idnumber); + if(it == map.end()) + return -1; + } + else + { + std::pair value; + value.first = idnumber; + memset(&value.second, 0, sizeof(value.second)); + for (unsigned i = 0; i < 128; ++i) + value.second.ins[i].flags = opnInstMeta::Flag_NoSound; + + std::pair ir; + if(flags & OPNMIDI_Bank_CreateRt) + { + ir = map.insert(value, OPN2::BankMap::do_not_expand_t()); + if(ir.first == map.end()) + return -1; + } + else + ir = map.insert(value); + it = ir.first; + } + + it.to_ptrs(bank->pointer); + return 0; +} + +OPNMIDI_EXPORT int opn2_getBankId(OPN2_MIDIPlayer *device, const OPN2_Bank *bank, OPN2_BankId *id) +{ + if(!device || !bank) + return -1; + + OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); + OPN2::BankMap::key_type idnumber = it->first; + id->msb = (idnumber >> 8) & 127; + id->lsb = idnumber & 127; + id->percussive = (idnumber & OPN2::PercussionTag) ? 1 : 0; + return 0; +} + +OPNMIDI_EXPORT int opn2_removeBank(OPN2_MIDIPlayer *device, OPN2_Bank *bank) +{ + if(!device || !bank) + return -1; + + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPN2::BankMap &map = play->m_synth.m_insBanks; + OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); + size_t size = map.size(); + map.erase(it); + return (map.size() != size) ? 0 : -1; +} + +OPNMIDI_EXPORT int opn2_getFirstBank(OPN2_MIDIPlayer *device, OPN2_Bank *bank) +{ + if(!device) + return -1; + + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPN2::BankMap &map = play->m_synth.m_insBanks; + + OPN2::BankMap::iterator it = map.begin(); + if(it == map.end()) + return -1; + + it.to_ptrs(bank->pointer); + return 0; +} + +OPNMIDI_EXPORT int opn2_getNextBank(OPN2_MIDIPlayer *device, OPN2_Bank *bank) +{ + if(!device) + return -1; + + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + OPN2::BankMap &map = play->m_synth.m_insBanks; + + OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); + if(++it == map.end()) + return -1; + + it.to_ptrs(bank->pointer); + return 0; +} + +OPNMIDI_EXPORT int opn2_getInstrument(OPN2_MIDIPlayer *device, const OPN2_Bank *bank, unsigned index, OPN2_Instrument *ins) +{ + if(!device || !bank || index > 127 || !ins) + return -1; + + OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); + cvt_FMIns_to_OPNI(*ins, it->second.ins[index]); + ins->version = 0; + return 0; +} + +OPNMIDI_EXPORT int opn2_setInstrument(OPN2_MIDIPlayer *device, OPN2_Bank *bank, unsigned index, const OPN2_Instrument *ins) +{ + if(!device || !bank || index > 127 || !ins) + return -1; + + if(ins->version != 0) + return -1; + + OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); + cvt_OPNI_to_FMIns(it->second.ins[index], *ins); + return 0; } OPNMIDI_EXPORT int opn2_openBankFile(OPN2_MIDIPlayer *device, const char *filePath) { - if(device && device->opn2_midiPlayer) + if(device) { - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadBank(filePath)) { @@ -105,7 +270,8 @@ OPNMIDI_EXPORT int opn2_openBankFile(OPN2_MIDIPlayer *device, const char *filePa play->setErrorString("OPN2 MIDI: Can't load file"); return -1; } - else return opn2RefreshNumCards(device); + else + return 0; } OPN2MIDI_ErrorString = "Can't load file: OPN2 MIDI is not initialized"; return -1; @@ -113,9 +279,10 @@ OPNMIDI_EXPORT int opn2_openBankFile(OPN2_MIDIPlayer *device, const char *filePa OPNMIDI_EXPORT int opn2_openBankData(OPN2_MIDIPlayer *device, const void *mem, long size) { - if(device && device->opn2_midiPlayer) + if(device) { - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadBank(mem, static_cast(size))) { @@ -131,53 +298,135 @@ OPNMIDI_EXPORT int opn2_openBankData(OPN2_MIDIPlayer *device, const void *mem, l return -1; } -OPNMIDI_EXPORT void opn2_setScaleModulators(OPN2_MIDIPlayer *device, int smod) +OPNMIDI_EXPORT void opn2_setLfoEnabled(struct OPN2_MIDIPlayer *device, int lfoEnable) { if(!device) return; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.lfoEnable = lfoEnable; + play->m_synth.m_lfoEnable = (lfoEnable < 0 ? + play->m_synth.m_insBankSetup.lfoEnable : + play->m_setup.lfoEnable) != 0; + play->m_synth.commitLFOSetup(); +} + +OPNMIDI_EXPORT int opn2_getLfoEnabled(struct OPN2_MIDIPlayer *device) +{ + if(!device) return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_synth.m_lfoEnable; +} + +OPNMIDI_EXPORT void opn2_setLfoFrequency(struct OPN2_MIDIPlayer *device, int lfoFrequency) +{ + if(!device) return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.lfoFrequency = lfoFrequency; + play->m_synth.m_lfoFrequency = lfoFrequency < 0 ? + play->m_synth.m_insBankSetup.lfoFrequency : + (uint8_t)play->m_setup.lfoFrequency; + play->m_synth.commitLFOSetup(); +} + +OPNMIDI_EXPORT int opn2_getLfoFrequency(struct OPN2_MIDIPlayer *device) +{ + if(!device) return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_synth.m_lfoFrequency; +} + +OPNMIDI_EXPORT void opn2_setScaleModulators(OPN2_MIDIPlayer *device, int smod) +{ + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->m_setup.ScaleModulators = smod; - play->opn.ScaleModulators = (play->m_setup.ScaleModulators != 0); + play->m_synth.m_scaleModulators = (play->m_setup.ScaleModulators != 0); } OPNMIDI_EXPORT void opn2_setFullRangeBrightness(struct OPN2_MIDIPlayer *device, int fr_brightness) { - if(!device) return; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->m_setup.fullRangeBrightnessCC74 = (fr_brightness != 0); } OPNMIDI_EXPORT void opn2_setLoopEnabled(OPN2_MIDIPlayer *device, int loopEn) { - if(!device) return; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - play->m_setup.loopingIsEnabled = (loopEn != 0); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER + play->m_sequencer.setLoopEnabled(loopEn != 0); +#else + ADL_UNUSED(loopEn); +#endif +} + +OPNMIDI_EXPORT void opn2_setSoftPanEnabled(OPN2_MIDIPlayer *device, int softPanEn) +{ + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_synth.m_softPanning = (softPanEn != 0); } /* !!!DEPRECATED!!! */ OPNMIDI_EXPORT void opn2_setLogarithmicVolumes(struct OPN2_MIDIPlayer *device, int logvol) { - if(!device) return; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->m_setup.LogarithmicVolumes = static_cast(logvol); - if(play->m_setup.LogarithmicVolumes != 0) - play->opn.ChangeVolumeRangesModel(OPNMIDI_VolumeModel_CMF); - else - play->opn.ChangeVolumeRangesModel(static_cast(play->m_setup.VolumeModel)); + if(!play->m_synth.setupLocked()) + { + if(play->m_setup.LogarithmicVolumes != 0) + play->m_synth.setVolumeScaleModel(OPNMIDI_VolumeModel_NativeOPN2); + else + play->m_synth.setVolumeScaleModel(static_cast(play->m_setup.VolumeModel)); + } } OPNMIDI_EXPORT void opn2_setVolumeRangeModel(OPN2_MIDIPlayer *device, int volumeModel) { - if(!device) return; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->m_setup.VolumeModel = volumeModel; - play->opn.ChangeVolumeRangesModel(static_cast(volumeModel)); + if(!play->m_synth.setupLocked()) + { + if(play->m_setup.VolumeModel == OPNMIDI_VolumeModel_AUTO)//Use bank default volume model + play->m_synth.m_volumeScale = (OPN2::VolumesScale)play->m_synth.m_insBankSetup.volumeModel; + else + play->m_synth.setVolumeScaleModel(static_cast(volumeModel)); + } +} + +OPNMIDI_EXPORT int opn2_getVolumeRangeModel(struct OPN2_MIDIPlayer *device) +{ + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_synth.getVolumeScaleModel(); } OPNMIDI_EXPORT int opn2_openFile(OPN2_MIDIPlayer *device, const char *filePath) { - if(device && device->opn2_midiPlayer) + if(device) { - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadMIDI(filePath)) @@ -189,7 +438,7 @@ OPNMIDI_EXPORT int opn2_openFile(OPN2_MIDIPlayer *device, const char *filePath) } else return 0; #else - (void)filePath; + ADL_UNUSED(filePath); play->setErrorString("OPNMIDI: MIDI Sequencer is not supported in this build of library!"); return -1; #endif @@ -201,9 +450,10 @@ OPNMIDI_EXPORT int opn2_openFile(OPN2_MIDIPlayer *device, const char *filePath) OPNMIDI_EXPORT int opn2_openData(OPN2_MIDIPlayer *device, const void *mem, unsigned long size) { - if(device && device->opn2_midiPlayer) + if(device) { - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER play->m_setup.tick_skip_samples_delay = 0; if(!play->LoadMIDI(mem, static_cast(size))) @@ -215,7 +465,8 @@ OPNMIDI_EXPORT int opn2_openData(OPN2_MIDIPlayer *device, const void *mem, unsig } else return 0; #else - (void)mem;(void)size; + ADL_UNUSED(mem); + ADL_UNUSED(size); play->setErrorString("OPNMIDI: MIDI Sequencer is not supported in this build of library!"); return -1; #endif @@ -234,9 +485,10 @@ OPNMIDI_EXPORT const char *opn2_chipEmulatorName(struct OPN2_MIDIPlayer *device) { if(device) { - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play && !play->opn.cardsOP2.empty()) - return play->opn.cardsOP2[0]->emulatorName(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + if(!play->m_synth.m_chips.empty()) + return play->m_synth.m_chips[0]->emulatorName(); } return "Unknown"; } @@ -245,11 +497,12 @@ OPNMIDI_EXPORT int opn2_switchEmulator(struct OPN2_MIDIPlayer *device, int emula { if(device) { - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play && (emulator >= 0) && (emulator < OPNMIDI_EMU_end)) + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + if(opn2_isEmulatorAvailable(emulator)) { play->m_setup.emulator = emulator; - opn2_reset(device); + play->partialReset(); return 0; } play->setErrorString("OPN2 MIDI: Unknown emulation core!"); @@ -262,13 +515,12 @@ OPNMIDI_EXPORT int opn2_setRunAtPcmRate(OPN2_MIDIPlayer *device, int enabled) { if(device) { - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - { - play->m_setup.runAtPcmRate = (enabled != 0); - opn2_reset(device); - return 0; - } + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_setup.runAtPcmRate = (enabled != 0); + if(!play->m_synth.setupLocked()) + play->partialReset(); + return 0; } return -1; } @@ -297,30 +549,19 @@ OPNMIDI_EXPORT const char *opn2_errorInfo(struct OPN2_MIDIPlayer *device) { if(!device) return opn2_errorString(); - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); if(!play) return opn2_errorString(); return play->getErrorString().c_str(); } -OPNMIDI_EXPORT const char *opn2_getMusicTitle(struct OPN2_MIDIPlayer *device) -{ - if(!device) - return ""; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(!play) - return ""; - return play->musTitle.c_str(); -#else - return ""; -#endif -} - OPNMIDI_EXPORT void opn2_close(OPN2_MIDIPlayer *device) { - if(device->opn2_midiPlayer) - delete reinterpret_cast(device->opn2_midiPlayer); + if(!device) + return; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + delete play; device->opn2_midiPlayer = NULL; free(device); device = NULL; @@ -330,154 +571,183 @@ OPNMIDI_EXPORT void opn2_reset(OPN2_MIDIPlayer *device) { if(!device) return; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - play->m_setup.tick_skip_samples_delay = 0; - play->opn.runAtPcmRate = play->m_setup.runAtPcmRate; - play->opn.Reset(play->m_setup.emulator, play->m_setup.PCM_RATE); - play->ch.clear(); - play->ch.resize(play->opn.NumChannels); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->partialReset(); + play->resetMIDI(); } OPNMIDI_EXPORT double opn2_totalTimeLength(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - return play->timeLength(); - else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.timeLength(); +#else + ADL_UNUSED(device); + return -1.0; #endif - return -1.0; } OPNMIDI_EXPORT double opn2_loopStartTime(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - return play->getLoopStart(); - else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getLoopStart(); +#else + ADL_UNUSED(device); + return -1.0; #endif - return -1.0; } OPNMIDI_EXPORT double opn2_loopEndTime(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - return play->getLoopEnd(); - else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getLoopEnd(); +#else + ADL_UNUSED(device); + return -1.0; #endif - return -1.0; } OPNMIDI_EXPORT double opn2_positionTell(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - return play->tell(); - else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.tell(); +#else + ADL_UNUSED(device); + return -1.0; #endif - return -1.0; } OPNMIDI_EXPORT void opn2_positionSeek(struct OPN2_MIDIPlayer *device, double seconds) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER + if(seconds < 0.0) + return;//Seeking negative position is forbidden! :-P if(!device) return; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - play->seek(seconds); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_panic(); + play->m_setup.delay = play->m_sequencer.seek(seconds, play->m_setup.mindelay); + play->m_setup.carry = 0.0; #else - (void)seconds; + ADL_UNUSED(device); + ADL_UNUSED(seconds); #endif } OPNMIDI_EXPORT void opn2_positionRewind(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - play->rewind(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_panic(); + play->m_sequencer.rewind(); +#else + ADL_UNUSED(device); #endif } OPNMIDI_EXPORT void opn2_setTempo(struct OPN2_MIDIPlayer *device, double tempo) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device || (tempo <= 0.0)) return; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - play->setTempo(tempo); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_sequencer.setTempo(tempo); +#else + ADL_UNUSED(device); + ADL_UNUSED(tempo); #endif } +OPNMIDI_EXPORT int opn2_describeChannels(struct OPN2_MIDIPlayer *device, char *str, char *attr, size_t size) +{ + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->describeChannels(str, attr, size); + return 0; +} + OPNMIDI_EXPORT const char *opn2_metaMusicTitle(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return ""; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - return play->musTitle.c_str(); - else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getMusicTitle().c_str(); +#else + ADL_UNUSED(device); + return ""; #endif - return ""; } OPNMIDI_EXPORT const char *opn2_metaMusicCopyright(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return ""; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - return play->musCopyright.c_str(); - else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getMusicCopyright().c_str(); +#else + ADL_UNUSED(device); + return 0; #endif - return ""; } OPNMIDI_EXPORT size_t opn2_metaTrackTitleCount(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return 0; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - return play->musTrackTitles.size(); - else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getTrackTitles().size(); +#else + ADL_UNUSED(device); + return 0; #endif - return 0; } OPNMIDI_EXPORT const char *opn2_metaTrackTitle(struct OPN2_MIDIPlayer *device, size_t index) { - if(!device) - return 0; #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(index >= play->musTrackTitles.size()) + if(!device) + return ""; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + const std::vector &titles = play->m_sequencer.getTrackTitles(); + if(index >= titles.size()) return "INVALID"; - return play->musTrackTitles[index].c_str(); + return titles[index].c_str(); #else - (void)index; + ADL_UNUSED(device); + ADL_UNUSED(index); return "NOT SUPPORTED"; #endif } @@ -485,36 +755,47 @@ OPNMIDI_EXPORT const char *opn2_metaTrackTitle(struct OPN2_MIDIPlayer *device, s OPNMIDI_EXPORT size_t opn2_metaMarkerCount(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return 0; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(play) - return play->musMarkers.size(); - else + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getMarkers().size(); +#else + ADL_UNUSED(device); + return 0; #endif - return 0; } OPNMIDI_EXPORT Opn2_MarkerEntry opn2_metaMarker(struct OPN2_MIDIPlayer *device, size_t index) { struct Opn2_MarkerEntry marker; + #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - if(!device || !play || (index >= play->musMarkers.size())) + if(!device) { marker.label = "INVALID"; marker.pos_time = 0.0; marker.pos_ticks = 0; return marker; } - else + + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + + const std::vector &markers = play->m_sequencer.getMarkers(); + if(index >= markers.size()) { - OPNMIDIplay::MIDI_MarkerEntry &mk = play->musMarkers[index]; - marker.label = mk.label.c_str(); - marker.pos_time = mk.pos_time; - marker.pos_ticks = (unsigned long)mk.pos_ticks; + marker.label = "INVALID"; + marker.pos_time = 0.0; + marker.pos_ticks = 0; + return marker; } + + const MidiSequencer::MIDI_MarkerEntry &mk = markers[index]; + marker.label = mk.label.c_str(); + marker.pos_time = mk.pos_time; + marker.pos_ticks = (unsigned long)mk.pos_ticks; #else (void)device; (void)index; marker.label = "NOT SUPPORTED"; @@ -526,11 +807,18 @@ OPNMIDI_EXPORT Opn2_MarkerEntry opn2_metaMarker(struct OPN2_MIDIPlayer *device, OPNMIDI_EXPORT void opn2_setRawEventHook(struct OPN2_MIDIPlayer *device, OPN2_RawEventHook rawEventHook, void *userData) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - play->hooks.onEvent = rawEventHook; - play->hooks.onEvent_userData = userData; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->m_sequencerInterface.onEvent = rawEventHook; + play->m_sequencerInterface.onEvent_userData = userData; +#else + ADL_UNUSED(device); + ADL_UNUSED(rawEventHook); + ADL_UNUSED(userData); +#endif } /* Set note hook */ @@ -538,7 +826,8 @@ OPNMIDI_EXPORT void opn2_setNoteHook(struct OPN2_MIDIPlayer *device, OPN2_NoteHo { if(!device) return; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->hooks.onNote = noteHook; play->hooks.onNote_userData = userData; } @@ -548,9 +837,14 @@ OPNMIDI_EXPORT void opn2_setDebugMessageHook(struct OPN2_MIDIPlayer *device, OPN { if(!device) return; - OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); play->hooks.onDebugMessage = debugMessageHook; play->hooks.onDebugMessage_userData = userData; +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER + play->m_sequencerInterface.onDebugMessage = debugMessageHook; + play->m_sequencerInterface.onDebugMessage_userData = userData; +#endif } @@ -570,8 +864,8 @@ static void CopySamplesTransformed(OPN2_UInt8 *dstLeft, OPN2_UInt8 *dstRight, co Ret(&transform)(int32_t)) { for(size_t i = 0; i < frameCount; ++i) { - *(Dst *)(dstLeft + (i * sampleOffset)) = transform(src[2 * i]); - *(Dst *)(dstRight + (i * sampleOffset)) = transform(src[(2 * i) + 1]); + *(Dst *)(dstLeft + (i * sampleOffset)) = static_cast(transform(src[2 * i])); + *(Dst *)(dstRight + (i * sampleOffset)) = static_cast(transform(src[(2 * i) + 1])); } } @@ -688,6 +982,15 @@ OPNMIDI_EXPORT int opn2_playFormat(OPN2_MIDIPlayer *device, int sampleCount, OPN2_UInt8 *out_left, OPN2_UInt8 *out_right, const OPNMIDI_AudioFormat *format) { +#if defined(OPNMIDI_DISABLE_MIDI_SEQUENCER) + ADL_UNUSED(device); + ADL_UNUSED(sampleCount); + ADL_UNUSED(out_left); + ADL_UNUSED(out_right); + ADL_UNUSED(format); + return 0; +#endif + #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER sampleCount -= sampleCount % 2; //Avoid even sample requests if(sampleCount < 0) @@ -695,8 +998,9 @@ OPNMIDI_EXPORT int opn2_playFormat(OPN2_MIDIPlayer *device, int sampleCount, if(!device) return 0; - OPNMIDIplay * player = (reinterpret_cast(device->opn2_midiPlayer)); - OPNMIDIplay::Setup &setup = player->m_setup; + MidiPlayer *player = GET_MIDI_PLAYER(device); + assert(player); + MidiPlayer::Setup &setup = player->m_setup; ssize_t gotten_len = 0; ssize_t n_periodCountStereo = 512; @@ -716,16 +1020,16 @@ OPNMIDI_EXPORT int opn2_playFormat(OPN2_MIDIPlayer *device, int sampleCount, else { setup.delay -= eat_delay; - setup.carry += setup.PCM_RATE * eat_delay; + setup.carry += double(setup.PCM_RATE) * eat_delay; n_periodCountStereo = static_cast(setup.carry); - setup.carry -= n_periodCountStereo; + setup.carry -= double(n_periodCountStereo); } //if(setup.SkipForward > 0) // setup.SkipForward -= 1; //else { - if((player->atEnd) && (setup.delay <= 0.0)) + if((player->m_sequencer.positionAtEnd()) && (setup.delay <= 0.0)) break;//Stop to fetch samples at reaching the song end with disabled loop ssize_t leftSamples = left / 2; @@ -740,16 +1044,16 @@ OPNMIDI_EXPORT int opn2_playFormat(OPN2_MIDIPlayer *device, int sampleCount, ssize_t in_generatedPhys = in_generatedStereo * 2; //! Unsigned total sample count //fill buffer with zeros - int32_t *out_buf = player->outBuf; + int32_t *out_buf = player->m_outBuf; std::memset(out_buf, 0, static_cast(in_generatedPhys) * sizeof(out_buf[0])); - unsigned int chips = player->opn.NumCards; + unsigned int chips = player->m_synth.m_numChips; if(chips == 1) - player->opn.cardsOP2[0]->generate32(out_buf, (size_t)in_generatedStereo); + player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); else/* if(n_periodCountStereo > 0)*/ { /* Generate data from every chip and mix result */ for(size_t card = 0; card < chips; ++card) - player->opn.cardsOP2[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); + player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); } /* Process it */ if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1) @@ -769,8 +1073,6 @@ OPNMIDI_EXPORT int opn2_playFormat(OPN2_MIDIPlayer *device, int sampleCount, } return static_cast(gotten_len); -#else - return 0; #endif //OPNMIDI_DISABLE_MIDI_SEQUENCER } @@ -790,8 +1092,9 @@ OPNMIDI_EXPORT int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampl if(!device) return 0; - OPNMIDIplay * player = (reinterpret_cast(device->opn2_midiPlayer)); - OPNMIDIplay::Setup &setup = player->m_setup; + MidiPlayer *player = GET_MIDI_PLAYER(device); + assert(player); + MidiPlayer::Setup &setup = player->m_setup; ssize_t gotten_len = 0; ssize_t n_periodCountStereo = 512; @@ -804,9 +1107,9 @@ OPNMIDI_EXPORT int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampl {// const double eat_delay = delay < setup.maxdelay ? delay : setup.maxdelay; delay -= eat_delay; - setup.carry += setup.PCM_RATE * eat_delay; + setup.carry += double(setup.PCM_RATE) * eat_delay; n_periodCountStereo = static_cast(setup.carry); - setup.carry -= n_periodCountStereo; + setup.carry -= double(n_periodCountStereo); { ssize_t leftSamples = left / 2; @@ -818,16 +1121,16 @@ OPNMIDI_EXPORT int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampl ssize_t in_generatedPhys = in_generatedStereo * 2; //! Unsigned total sample count //fill buffer with zeros - int32_t *out_buf = player->outBuf; + int32_t *out_buf = player->m_outBuf; std::memset(out_buf, 0, static_cast(in_generatedPhys) * sizeof(out_buf[0])); - unsigned int chips = player->opn.NumCards; + unsigned int chips = player->m_synth.m_numChips; if(chips == 1) - player->opn.cardsOP2[0]->generate32(out_buf, (size_t)in_generatedStereo); + player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); else/* if(n_periodCountStereo > 0)*/ { /* Generate data from every chip and mix result */ for(size_t card = 0; card < chips; ++card) - player->opn.cardsOP2[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); + player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); } /* Process it */ if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1) @@ -837,8 +1140,8 @@ OPNMIDI_EXPORT int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampl gotten_len += (in_generatedPhys) /* - setup.stored_samples*/; } - player->TickIteratos(eat_delay); - }// + player->TickIterators(eat_delay); + }//... } return static_cast(gotten_len); @@ -846,159 +1149,211 @@ OPNMIDI_EXPORT int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampl OPNMIDI_EXPORT double opn2_tickEvents(struct OPN2_MIDIPlayer *device, double seconds, double granuality) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return -1.0; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return -1.0; - return player->Tick(seconds, granuality); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->Tick(seconds, granuality); #else - (void)seconds; (void)granuality; + ADL_UNUSED(device); + ADL_UNUSED(seconds); + ADL_UNUSED(granuality); return -1.0; #endif } OPNMIDI_EXPORT int opn2_atEnd(struct OPN2_MIDIPlayer *device) { +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER if(!device) return 1; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return 1; - return (int)player->atEnd; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return (int)play->m_sequencer.positionAtEnd(); #else + ADL_UNUSED(device); return 1; #endif } +OPNMIDI_EXPORT size_t opn2_trackCount(struct OPN2_MIDIPlayer *device) +{ +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER + if(!device) + return 0; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->m_sequencer.getTrackCount(); +#else + ADL_UNUSED(device); + return 0; +#endif +} + +OPNMIDI_EXPORT int opn2_setTrackOptions(struct OPN2_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions) +{ +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + MidiSequencer &seq = play->m_sequencer; + + unsigned enableFlag = trackOptions & 3; + trackOptions &= ~3u; + + // handle on/off/solo + switch(enableFlag) + { + default: + break; + case OPNMIDI_TrackOption_On: + case OPNMIDI_TrackOption_Off: + if(!seq.setTrackEnabled(trackNumber, enableFlag == OPNMIDI_TrackOption_On)) + return -1; + break; + case OPNMIDI_TrackOption_Solo: + seq.setSoloTrack(trackNumber); + break; + } + + // handle others... + if(trackOptions != 0) + return -1; + + return 0; + +#else + ADL_UNUSED(device); + ADL_UNUSED(trackNumber); + ADL_UNUSED(trackOptions); + return -1; +#endif +} + OPNMIDI_EXPORT void opn2_panic(struct OPN2_MIDIPlayer *device) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_panic(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_panic(); } OPNMIDI_EXPORT void opn2_rt_resetState(struct OPN2_MIDIPlayer *device) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_ResetState(); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_ResetState(); } OPNMIDI_EXPORT int opn2_rt_noteOn(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 velocity) { if(!device) return 0; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return 0; - return (int)player->realTime_NoteOn(channel, note, velocity); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return (int)play->realTime_NoteOn(channel, note, velocity); } OPNMIDI_EXPORT void opn2_rt_noteOff(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_NoteOff(channel, note); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_NoteOff(channel, note); } OPNMIDI_EXPORT void opn2_rt_noteAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 atVal) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_NoteAfterTouch(channel, note, atVal); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_NoteAfterTouch(channel, note, atVal); } OPNMIDI_EXPORT void opn2_rt_channelAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 atVal) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_ChannelAfterTouch(channel, atVal); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_ChannelAfterTouch(channel, atVal); } OPNMIDI_EXPORT void opn2_rt_controllerChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 type, OPN2_UInt8 value) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_Controller(channel, type, value); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_Controller(channel, type, value); } OPNMIDI_EXPORT void opn2_rt_patchChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 patch) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_PatchChange(channel, patch); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_PatchChange(channel, patch); } OPNMIDI_EXPORT void opn2_rt_pitchBend(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt16 pitch) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_PitchBend(channel, pitch); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_PitchBend(channel, pitch); } OPNMIDI_EXPORT void opn2_rt_pitchBendML(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb, OPN2_UInt8 lsb) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_PitchBend(channel, msb, lsb); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_PitchBend(channel, msb, lsb); } OPNMIDI_EXPORT void opn2_rt_bankChangeLSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 lsb) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_BankChangeLSB(channel, lsb); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_BankChangeLSB(channel, lsb); } OPNMIDI_EXPORT void opn2_rt_bankChangeMSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_BankChangeMSB(channel, msb); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_BankChangeMSB(channel, msb); } OPNMIDI_EXPORT void opn2_rt_bankChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_SInt16 bank) { if(!device) return; - OPNMIDIplay *player = reinterpret_cast(device->opn2_midiPlayer); - if(!player) - return; - player->realTime_BankChange(channel, (uint16_t)bank); + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + play->realTime_BankChange(channel, (uint16_t)bank); +} + +OPNMIDI_EXPORT int opn2_rt_systemExclusive(struct OPN2_MIDIPlayer *device, const OPN2_UInt8 *msg, size_t size) +{ + if(!device) + return -1; + MidiPlayer *play = GET_MIDI_PLAYER(device); + assert(play); + return play->realTime_SysEx(msg, size); } diff --git a/src/sound/opnmidi/opnmidi.h b/src/sound/opnmidi/opnmidi.h index 29ac58f86..5f2cd78e5 100644 --- a/src/sound/opnmidi/opnmidi.h +++ b/src/sound/opnmidi/opnmidi.h @@ -29,7 +29,7 @@ extern "C" { #endif #define OPNMIDI_VERSION_MAJOR 1 -#define OPNMIDI_VERSION_MINOR 3 +#define OPNMIDI_VERSION_MINOR 4 #define OPNMIDI_VERSION_PATCHLEVEL 0 #define OPNMIDI_TOSTR_I(s) #s @@ -54,195 +54,727 @@ typedef char OPN2_SInt8; typedef short OPN2_SInt16; #endif + +/* == Deprecated function markers == */ + +#if defined(_MSC_VER) /* MSVC */ +# if _MSC_VER >= 1500 /* MSVC 2008 */ + /*! Indicates that the following function is deprecated. */ +# define OPNMIDI_DEPRECATED(message) __declspec(deprecated(message)) +# endif +#endif /* defined(_MSC_VER) */ + +#ifdef __clang__ +# if __has_extension(attribute_deprecated_with_message) +# define OPNMIDI_DEPRECATED(message) __attribute__((deprecated(message))) +# endif +#elif defined __GNUC__ /* not clang (gcc comes later since clang emulates gcc) */ +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define OPNMIDI_DEPRECATED(message) __attribute__((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define OPNMIDI_DEPRECATED(message) __attribute__((__deprecated__)) +# endif /* GNUC version */ +#endif /* __clang__ || __GNUC__ */ + +#if !defined(OPNMIDI_DEPRECATED) +# define OPNMIDI_DEPRECATED(message) +#endif /* if !defined(OPNMIDI_DEPRECATED) */ + + +#ifdef OPNMIDI_BUILD +# ifndef OPNMIDI_DECLSPEC +# if defined (_WIN32) && defined(OPNMIDI_BUILD_DLL) +# define OPNMIDI_DECLSPEC __declspec(dllexport) +# else +# define OPNMIDI_DECLSPEC +# endif +# endif +#else +# define OPNMIDI_DECLSPEC +#endif + +/** + * @brief Volume scaling models + */ enum OPNMIDI_VolumeModels { + /*! Automatical choice by the specific bank */ OPNMIDI_VolumeModel_AUTO = 0, + /*! Linearized scaling model, most standard */ OPNMIDI_VolumeModel_Generic, - OPNMIDI_VolumeModel_CMF, + /*! Native OPN2's logarithmic volume scale */ + OPNMIDI_VolumeModel_NativeOPN2, + /*! Logarithmic volume scale, using volume map table. Used in DMX. */ OPNMIDI_VolumeModel_DMX, + /*! Logarithmic volume scale, used in Apogee Sound System. */ OPNMIDI_VolumeModel_APOGEE, + /*! Aproximated and shorted volume map table. Similar to general, but has less granularity. */ OPNMIDI_VolumeModel_9X }; +/** + * @brief Sound output format + */ enum OPNMIDI_SampleType { - OPNMIDI_SampleType_S16 = 0, /* signed PCM 16-bit */ - OPNMIDI_SampleType_S8, /* signed PCM 8-bit */ - OPNMIDI_SampleType_F32, /* float 32-bit */ - OPNMIDI_SampleType_F64, /* float 64-bit */ - OPNMIDI_SampleType_S24, /* signed PCM 24-bit */ - OPNMIDI_SampleType_S32, /* signed PCM 32-bit */ - OPNMIDI_SampleType_U8, /* unsigned PCM 8-bit */ - OPNMIDI_SampleType_U16, /* unsigned PCM 16-bit */ - OPNMIDI_SampleType_U24, /* unsigned PCM 24-bit */ - OPNMIDI_SampleType_U32, /* unsigned PCM 32-bit */ + /*! signed PCM 16-bit */ + OPNMIDI_SampleType_S16 = 0, + /*! signed PCM 8-bit */ + OPNMIDI_SampleType_S8, + /*! float 32-bit */ + OPNMIDI_SampleType_F32, + /*! float 64-bit */ + OPNMIDI_SampleType_F64, + /*! signed PCM 24-bit */ + OPNMIDI_SampleType_S24, + /*! signed PCM 32-bit */ + OPNMIDI_SampleType_S32, + /*! unsigned PCM 8-bit */ + OPNMIDI_SampleType_U8, + /*! unsigned PCM 16-bit */ + OPNMIDI_SampleType_U16, + /*! unsigned PCM 24-bit */ + OPNMIDI_SampleType_U24, + /*! unsigned PCM 32-bit */ + OPNMIDI_SampleType_U32, + /*! Count of available sample format types */ OPNMIDI_SampleType_Count, }; +/** + * @brief Sound output format context + */ struct OPNMIDI_AudioFormat { - enum OPNMIDI_SampleType type; /* type of sample */ - unsigned containerSize; /* size in bytes of the storage type */ - unsigned sampleOffset; /* distance in bytes between consecutive samples */ + /*! type of sample */ + enum OPNMIDI_SampleType type; + /*! size in bytes of the storage type */ + unsigned containerSize; + /*! distance in bytes between consecutive samples */ + unsigned sampleOffset; }; +/** + * @brief Instance of the library + */ struct OPN2_MIDIPlayer { + /*! Private context descriptor */ void *opn2_midiPlayer; }; /* DEPRECATED */ #define opn2_setNumCards opn2_setNumChips -/* Sets number of emulated sound cards (from 1 to 100). Emulation of multiple sound cards exchanges polyphony limits*/ -extern int opn2_setNumChips(struct OPN2_MIDIPlayer *device, int numCards); +/** + * @brief Sets number of emulated chips (from 1 to 100). Emulation of multiple chips extends polyphony limits + * @param device Instance of the library + * @param numChips Count of virtual chips to emulate + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_setNumChips(struct OPN2_MIDIPlayer *device, int numCards); -/* Get current number of emulated chips */ -extern int opn2_getNumChips(struct OPN2_MIDIPlayer *device); +/** + * @brief Get current number of emulated chips + * @param device Instance of the library + * @return Count of working chip emulators + */ +extern OPNMIDI_DECLSPEC int opn2_getNumChips(struct OPN2_MIDIPlayer *device); -/*Enable or disable Enables scaling of modulator volumes*/ -extern void opn2_setScaleModulators(struct OPN2_MIDIPlayer *device, int smod); +/** + * @brief Get obtained number of emulated chips + * @param device Instance of the library + * @return Count of working chip emulators + */ +extern OPNMIDI_DECLSPEC int opn2_getNumChipsObtained(struct OPN2_MIDIPlayer *device); -/*Enable(1) or Disable(0) full-range brightness (MIDI CC74 used in XG music to filter result sounding) scaling. - By default, brightness affects sound between 0 and 64. - When this option is enabled, the range will use a full range from 0 up to 127. -*/ -extern void opn2_setFullRangeBrightness(struct OPN2_MIDIPlayer *device, int fr_brightness); +/** + * @brief Reference to dynamic bank + */ +typedef struct OPN2_Bank +{ + void *pointer[3]; +} OPN2_Bank; -/*Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part)*/ -extern void opn2_setLoopEnabled(struct OPN2_MIDIPlayer *device, int loopEn); +/** + * @brief Identifier of dynamic bank + */ +typedef struct OPN2_BankId +{ + /*! 0 if bank is melodic set, or 1 if bank is a percussion set */ + OPN2_UInt8 percussive; + /*! Assign to MSB bank number */ + OPN2_UInt8 msb; + /*! Assign to LSB bank number */ + OPN2_UInt8 lsb; +} OPN2_BankId; -/* !!!DEPRECATED!!! */ -extern void opn2_setLogarithmicVolumes(struct OPN2_MIDIPlayer *device, int logvol); +/** + * @brief Flags for dynamic bank access + */ +enum OPN2_BankAccessFlags +{ + /*! create bank, allocating memory as needed */ + OPNMIDI_Bank_Create = 1, + /*! create bank, never allocating memory */ + OPNMIDI_Bank_CreateRt = 1|2 +}; -/*Set different volume range model */ -extern void opn2_setVolumeRangeModel(struct OPN2_MIDIPlayer *device, int volumeModel); - -/*Load WOPN bank file from File System. Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time.*/ -extern int opn2_openBankFile(struct OPN2_MIDIPlayer *device, const char *filePath); - -/*Load WOPN bank file from memory data*/ -extern int opn2_openBankData(struct OPN2_MIDIPlayer *device, const void *mem, long size); +typedef struct OPN2_Instrument OPN2_Instrument; -/* DEPRECATED */ -extern const char *opn2_emulatorName(); -/*Returns chip emulator name string*/ -extern const char *opn2_chipEmulatorName(struct OPN2_MIDIPlayer *device); +/* ======== Setup ======== */ + +#ifdef OPNMIDI_UNSTABLE_API + +/** + * @brief Preallocates a minimum number of bank slots. Returns the actual capacity + * @param device Instance of the library + * @param banks Count of bank slots to pre-allocate. + * @return actual capacity of reserved bank slots. + */ +extern OPNMIDI_DECLSPEC int opn2_reserveBanks(struct OPN2_MIDIPlayer *device, unsigned banks); +/** + * @brief Gets the bank designated by the identifier, optionally creating if it does not exist + * @param device Instance of the library + * @param id Identifier of dynamic bank + * @param flags Flags for dynamic bank access (OPN2_BankAccessFlags) + * @param bank Reference to dynamic bank + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_getBank(struct OPN2_MIDIPlayer *device, const OPN2_BankId *id, int flags, OPN2_Bank *bank); +/** + * @brief Gets the identifier of a bank + * @param device Instance of the library + * @param bank Reference to dynamic bank. + * @param id Identifier of dynamic bank + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_getBankId(struct OPN2_MIDIPlayer *device, const OPN2_Bank *bank, OPN2_BankId *id); +/** + * @brief Removes a bank + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_removeBank(struct OPN2_MIDIPlayer *device, OPN2_Bank *bank); +/** + * @brief Gets the first bank + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_getFirstBank(struct OPN2_MIDIPlayer *device, OPN2_Bank *bank); +/** + * @brief Iterates to the next bank + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @return 0 on success, <0 when any error has occurred or end has been reached. + */ +extern OPNMIDI_DECLSPEC int opn2_getNextBank(struct OPN2_MIDIPlayer *device, OPN2_Bank *bank); +/** + * @brief Gets the nth intrument in the bank [0..127] + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @param index Index of the instrument + * @param ins Instrument entry + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_getInstrument(struct OPN2_MIDIPlayer *device, const OPN2_Bank *bank, unsigned index, OPN2_Instrument *ins); +/** + * @brief Sets the nth intrument in the bank [0..127] + * @param device Instance of the library + * @param bank Reference to dynamic bank + * @param index Index of the instrument + * @param ins Instrument structure pointer + * @return 0 on success, <0 when any error has occurred + * + * This function allows to override an instrument on the fly + */ +extern OPNMIDI_DECLSPEC int opn2_setInstrument(struct OPN2_MIDIPlayer *device, OPN2_Bank *bank, unsigned index, const OPN2_Instrument *ins); + +#endif /* OPNMIDI_UNSTABLE_API */ + + + +/*Override Enable(1) or Disable(0) LFO. -1 - use bank default state*/ +extern OPNMIDI_DECLSPEC void opn2_setLfoEnabled(struct OPN2_MIDIPlayer *device, int lfoEnable); + +/*Get the LFO state*/ +extern OPNMIDI_DECLSPEC int opn2_getLfoEnabled(struct OPN2_MIDIPlayer *device); + +/*Override LFO frequency. -1 - use bank default state*/ +extern OPNMIDI_DECLSPEC void opn2_setLfoFrequency(struct OPN2_MIDIPlayer *device, int lfoFrequency); + +/*Get the LFO frequency*/ +extern OPNMIDI_DECLSPEC int opn2_getLfoFrequency(struct OPN2_MIDIPlayer *device); + +/** + * @brief Override Enable(1) or Disable(0) scaling of modulator volumes. -1 - use bank default scaling of modulator volumes + * @param device Instance of the library + * @param smod 0 - disabled, 1 - enabled + */ +extern OPNMIDI_DECLSPEC void opn2_setScaleModulators(struct OPN2_MIDIPlayer *device, int smod); + +/** + * @brief Enable(1) or Disable(0) full-range brightness (MIDI CC74 used in XG music to filter result sounding) scaling + * + * By default, brightness affects sound between 0 and 64. + * When this option is enabled, the brightness will use full range from 0 up to 127. + * + * @param device Instance of the library + * @param fr_brightness 0 - disabled, 1 - enabled + */ +extern OPNMIDI_DECLSPEC void opn2_setFullRangeBrightness(struct OPN2_MIDIPlayer *device, int fr_brightness); + +/** + * @brief Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part) + * @param device Instance of the library + * @param loopEn 0 - disabled, 1 - enabled + */ +extern OPNMIDI_DECLSPEC void opn2_setLoopEnabled(struct OPN2_MIDIPlayer *device, int loopEn); + +/** + * @brief Enable or disable soft panning with chip emulators + * @param device Instance of the library + * @param softPanEn 0 - disabled, 1 - enabled + */ +extern OPNMIDI_DECLSPEC void opn2_setSoftPanEnabled(struct OPN2_MIDIPlayer *device, int softPanEn); + +/** + * @brief [DEPRECATED] Enable or disable Logarithmic volume changer + * + * This function is deprecated. Suggested replacement: `opn2_setVolumeRangeModel` with `OPNMIDI_VolumeModel_NativeOPN2` volume model value; + */ +OPNMIDI_DEPRECATED("Use `opn2_setVolumeRangeModel(device, OPNMIDI_VolumeModel_NativeOPN2)` instead") +extern OPNMIDI_DECLSPEC void opn2_setLogarithmicVolumes(struct OPN2_MIDIPlayer *device, int logvol); + +/** + * @brief Set different volume range model + * @param device Instance of the library + * @param volumeModel Volume model type (#OPNMIDI_VolumeModels) + */ +extern OPNMIDI_DECLSPEC void opn2_setVolumeRangeModel(struct OPN2_MIDIPlayer *device, int volumeModel); + +/** + * @brief Get the volume range model + * @param device Instance of the library + * @return volume model on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_getVolumeRangeModel(struct OPN2_MIDIPlayer *device); + +/** + * @brief Load WOPN bank file from File System + * + * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. + * + * @param device Instance of the library + * @param filePath Absolute or relative path to the WOPL bank file. UTF8 encoding is required, even on Windows. + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_openBankFile(struct OPN2_MIDIPlayer *device, const char *filePath); + +/** + * @brief Load WOPN bank file from memory data + * + * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. + * + * @param device Instance of the library + * @param mem Pointer to memory block where is raw data of WOPL bank file is stored + * @param size Size of given memory block + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_openBankData(struct OPN2_MIDIPlayer *device, const void *mem, long size); + + +/** + * @brief [DEPRECATED] Dummy function + * + * This function is deprecated. Suggested replacement: `opn2_chipEmulatorName` + * + * @return A string that contains a notice to use `opn2_chipEmulatorName` instead of this function. + */ +OPNMIDI_DEPRECATED("Use `adl_chipEmulatorName(device)` instead") +extern OPNMIDI_DECLSPEC const char *opn2_emulatorName(); + +/** + * @brief Returns chip emulator name string + * @param device Instance of the library + * @return Understandable name of current OPN2 emulator + */ +extern OPNMIDI_DECLSPEC const char *opn2_chipEmulatorName(struct OPN2_MIDIPlayer *device); + +/** + * @brief List of available OPN2 emulators + */ enum Opn2_Emulator { + /*! Mame YM2612 */ OPNMIDI_EMU_MAME = 0, + /*! Nuked OPN2 */ OPNMIDI_EMU_NUKED, + /*! GENS */ OPNMIDI_EMU_GENS, + /*! Genesis Plus GX (a fork of Mame YM2612) */ OPNMIDI_EMU_GX, + /*! Count instrument on the level */ OPNMIDI_EMU_end }; -/* Switch the emulation core */ -extern int opn2_switchEmulator(struct OPN2_MIDIPlayer *device, int emulator); +/** + * @brief Switch the emulation core + * @param device Instance of the library + * @param emulator Type of emulator (#Opn2_Emulator) + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_switchEmulator(struct OPN2_MIDIPlayer *device, int emulator); +/** + * @brief Library version context + */ typedef struct { OPN2_UInt16 major; OPN2_UInt16 minor; OPN2_UInt16 patch; } OPN2_Version; -/*Run emulator with PCM rate to reduce CPU usage on slow devices. May decrease sounding accuracy.*/ -extern int opn2_setRunAtPcmRate(struct OPN2_MIDIPlayer *device, int enabled); +/** + * @brief Run emulator with PCM rate to reduce CPU usage on slow devices. + * + * May decrease sounding accuracy on some chip emulators. + * + * @param device Instance of the library + * @param enabled 0 - disabled, 1 - enabled + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_setRunAtPcmRate(struct OPN2_MIDIPlayer *device, int enabled); -/*Returns string which contains a version number*/ -extern const char *opn2_linkedLibraryVersion(); +/** + * @brief Set 4-bit device identifier. Used by the SysEx processor. + * @param device Instance of the library + * @param id 4-bit device identifier + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_setDeviceIdentifier(struct OPN2_MIDIPlayer *device, unsigned id); -/*Returns structure which contains a version number of library */ -extern const OPN2_Version *opn2_linkedVersion(); -/*Returns string which contains last error message*/ -extern const char *opn2_errorString(); +/** + * @section Information + */ -/*Returns string which contains last error message on specific device*/ -extern const char *opn2_errorInfo(struct OPN2_MIDIPlayer *device); +/** + * @brief Returns string which contains a version number + * @return String which contains a version of the library + */ +extern OPNMIDI_DECLSPEC const char *opn2_linkedLibraryVersion(); -/*Initialize ADLMIDI Player device*/ -extern struct OPN2_MIDIPlayer *opn2_init(long sample_rate); +/** + * @brief Returns structure which contains a version number of library + * @return Library version context structure which contains version number of the library + */ +extern OPNMIDI_DECLSPEC const OPN2_Version *opn2_linkedVersion(); -/*Load MIDI file from File System*/ -extern int opn2_openFile(struct OPN2_MIDIPlayer *device, const char *filePath); +/** + * @brief Returns string which contains last error message of initialization + * + * Don't use this function to get info on any function except of `opn2_init`! + * Use `opn2_errorInfo()` to get error information while workflow + * + * @return String with error message related to library initialization + */ +extern OPNMIDI_DECLSPEC const char *opn2_errorString(); -/*Load MIDI file from memory data*/ -extern int opn2_openData(struct OPN2_MIDIPlayer *device, const void *mem, unsigned long size); +/** + * @brief Returns string which contains last error message on specific device + * @param device Instance of the library + * @return String with error message related to last function call returned non-zero value. + */ +extern OPNMIDI_DECLSPEC const char *opn2_errorInfo(struct OPN2_MIDIPlayer *device); -/*Resets MIDI player*/ -extern void opn2_reset(struct OPN2_MIDIPlayer *device); -/*Get total time length of current song*/ -extern double opn2_totalTimeLength(struct OPN2_MIDIPlayer *device); +/* ======== Initialization ======== */ -/*Get loop start time if presented. -1 means MIDI file has no loop points */ -extern double opn2_loopStartTime(struct OPN2_MIDIPlayer *device); +/** + * @brief Initialize OPNMIDI Player device + * + * Tip 1: You can initialize multiple instances and run them in parallel + * Tip 2: Library is NOT thread-safe, therefore don't use same instance in different threads or use mutexes + * Tip 3: Changing of sample rate on the fly is not supported. Re-create the instance again. + * + * @param sample_rate Output sample rate + * @return Instance of the library. If NULL was returned, check the `adl_errorString` message for more info. + */ +extern OPNMIDI_DECLSPEC struct OPN2_MIDIPlayer *opn2_init(long sample_rate); -/*Get loop end time if presented. -1 means MIDI file has no loop points */ -extern double opn2_loopEndTime(struct OPN2_MIDIPlayer *device); +/** + * @brief Close and delete OPNMIDI device + * @param device Instance of the library + */ +extern OPNMIDI_DECLSPEC void opn2_close(struct OPN2_MIDIPlayer *device); -/*Get current time position in seconds*/ -extern double opn2_positionTell(struct OPN2_MIDIPlayer *device); -/*Jump to absolute time position in seconds*/ -extern void opn2_positionSeek(struct OPN2_MIDIPlayer *device, double seconds); +/* ======== MIDI Sequencer ======== */ -/*Reset MIDI track position to begin */ -extern void opn2_positionRewind(struct OPN2_MIDIPlayer *device); +/** + * @brief Load MIDI (or any other supported format) file from File System + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param filePath Absolute or relative path to the music file. UTF8 encoding is required, even on Windows. + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_openFile(struct OPN2_MIDIPlayer *device, const char *filePath); -/*Set tempo multiplier: 1.0 - original tempo, >1 - play faster, <1 - play slower */ -extern void opn2_setTempo(struct OPN2_MIDIPlayer *device, double tempo); +/** + * @brief Load MIDI (or any other supported format) file from memory data + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param mem Pointer to memory block where is raw data of music file is stored + * @param size Size of given memory block + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_openData(struct OPN2_MIDIPlayer *device, const void *mem, unsigned long size); -/*Close and delete OPNMIDI device*/ -extern void opn2_close(struct OPN2_MIDIPlayer *device); +/** + * @brief Resets MIDI player (per-channel setup) into initial state + * @param device Instance of the library + */ +extern OPNMIDI_DECLSPEC void opn2_reset(struct OPN2_MIDIPlayer *device); + +/** + * @brief Get total time length of current song + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @return Total song length in seconds + */ +extern OPNMIDI_DECLSPEC double opn2_totalTimeLength(struct OPN2_MIDIPlayer *device); + +/** + * @brief Get loop start time if presented. + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @return Time position in seconds of loop start point, or -1 when file has no loop points + */ +extern OPNMIDI_DECLSPEC double opn2_loopStartTime(struct OPN2_MIDIPlayer *device); + +/** + * @brief Get loop endtime if presented. + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @return Time position in seconds of loop end point, or -1 when file has no loop points + */ +extern OPNMIDI_DECLSPEC double opn2_loopEndTime(struct OPN2_MIDIPlayer *device); + +/** + * @brief Get current time position in seconds + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @return Current time position in seconds + */ +extern OPNMIDI_DECLSPEC double opn2_positionTell(struct OPN2_MIDIPlayer *device); + +/** + * @brief Jump to absolute time position in seconds + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param seconds Destination time position in seconds to seek + */ +extern OPNMIDI_DECLSPEC void opn2_positionSeek(struct OPN2_MIDIPlayer *device, double seconds); + +/** + * @brief Reset MIDI track position to begin + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + */ +extern OPNMIDI_DECLSPEC void opn2_positionRewind(struct OPN2_MIDIPlayer *device); + +/** + * @brief Set tempo multiplier + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param tempo Tempo multiplier value: 1.0 - original tempo, >1 - play faster, <1 - play slower + */ +extern OPNMIDI_DECLSPEC void opn2_setTempo(struct OPN2_MIDIPlayer *device, double tempo); + +/** + * @brief Returns 1 if music position has reached end + * @param device Instance of the library + * @return 1 when end of sing has been reached, otherwise, 0 will be returned. <0 is returned on any error + */ +extern OPNMIDI_DECLSPEC int opn2_atEnd(struct OPN2_MIDIPlayer *device); + +/** + * @brief Returns the number of tracks of the current sequence + * @param device Instance of the library + * @return Count of tracks in the current sequence + */ +extern OPNMIDI_DECLSPEC size_t opn2_trackCount(struct OPN2_MIDIPlayer *device); -/**META**/ +/* ======== Meta-Tags ======== */ -/*Returns string which contains a music title*/ -extern const char *opn2_metaMusicTitle(struct OPN2_MIDIPlayer *device); +/** + * @brief Returns string which contains a music title + * @param device Instance of the library + * @return A string that contains music title + */ +extern OPNMIDI_DECLSPEC const char *opn2_metaMusicTitle(struct OPN2_MIDIPlayer *device); -/*Returns string which contains a copyright string*/ -extern const char *opn2_metaMusicCopyright(struct OPN2_MIDIPlayer *device); +/** + * @brief Returns string which contains a copyright string* + * @param device Instance of the library + * @return A string that contains copyright notice, otherwise NULL + */ +extern OPNMIDI_DECLSPEC const char *opn2_metaMusicCopyright(struct OPN2_MIDIPlayer *device); -/*Returns count of available track titles: NOTE: there are CAN'T be associated with channel in any of event or note hooks */ -extern size_t opn2_metaTrackTitleCount(struct OPN2_MIDIPlayer *device); +/** + * @brief Returns count of available track titles + * + * NOTE: There are CAN'T be associated with channel in any of event or note hooks + * + * @param device Instance of the library + * @return Count of available MIDI tracks, otherwise NULL + */ +extern OPNMIDI_DECLSPEC size_t opn2_metaTrackTitleCount(struct OPN2_MIDIPlayer *device); -/*Get track title by index*/ -extern const char *opn2_metaTrackTitle(struct OPN2_MIDIPlayer *device, size_t index); +/** + * @brief Get track title by index + * @param device Instance of the library + * @param index Index of the track to retreive the title + * @return A string that contains track title, otherwise NULL. + */ +extern OPNMIDI_DECLSPEC const char *opn2_metaTrackTitle(struct OPN2_MIDIPlayer *device, size_t index); +/** + * @brief MIDI Marker structure + */ struct Opn2_MarkerEntry { + /*! MIDI Marker title */ const char *label; + /*! Absolute time position of the marker in seconds */ double pos_time; + /*! Absolute time position of the marker in MIDI ticks */ unsigned long pos_ticks; }; -/*Returns count of available markers*/ -extern size_t opn2_metaMarkerCount(struct OPN2_MIDIPlayer *device); +/** + * @brief Returns count of available markers + * @param device Instance of the library + * @return Count of available MIDI markers + */ +extern OPNMIDI_DECLSPEC size_t opn2_metaMarkerCount(struct OPN2_MIDIPlayer *device); -/*Returns the marker entry*/ -extern struct Opn2_MarkerEntry opn2_metaMarker(struct OPN2_MIDIPlayer *device, size_t index); +/** + * @brief Returns the marker entry + * @param device Instance of the library + * @param index Index of the marker to retreive it. + * @return MIDI Marker description structure. + */ +extern OPNMIDI_DECLSPEC struct Opn2_MarkerEntry opn2_metaMarker(struct OPN2_MIDIPlayer *device, size_t index); -/*Take a sample buffer and iterate MIDI timers */ -extern int opn2_play(struct OPN2_MIDIPlayer *device, int sampleCount, short *out); +/* ======== Audio output Generation ======== */ -/*Take a sample buffer and iterate MIDI timers */ -extern int opn2_playFormat(struct OPN2_MIDIPlayer *device, int sampleCount, OPN2_UInt8 *left, OPN2_UInt8 *right, const struct OPNMIDI_AudioFormat *format); +/** + * @brief Generate PCM signed 16-bit stereo audio output and iterate MIDI timers + * + * Use this function when you are playing MIDI file loaded by `adl_openFile` or by `adl_openData` + * with using of built-in MIDI sequencer. + * + * Don't use count of frames, use instead count of samples. One frame is two samples. + * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param sampleCount Count of samples (not frames!) + * @param out Pointer to output with 16-bit stereo PCM output + * @return Count of given samples, otherwise, 0 or when catching an error while playing + */ +extern OPNMIDI_DECLSPEC int opn2_play(struct OPN2_MIDIPlayer *device, int sampleCount, short *out); -/*Generate audio output from chip emulators without iteration of MIDI timers.*/ -extern int opn2_generate(struct OPN2_MIDIPlayer *device, int sampleCount, short *out); +/** + * @brief Generate PCM stereo audio output in sample format declared by given context and iterate MIDI timers + * + * Use this function when you are playing MIDI file loaded by `adl_openFile` or by `adl_openData` + * with using of built-in MIDI sequencer. + * + * Don't use count of frames, use instead count of samples. One frame is two samples. + * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! + * + * Available when library is built with built-in MIDI Sequencer support. + * + * @param device Instance of the library + * @param sampleCount Count of samples (not frames!) + * @param left Left channel buffer output (Must be casted into bytes array) + * @param right Right channel buffer output (Must be casted into bytes array) + * @param format Destination PCM format format context + * @return Count of given samples, otherwise, 0 or when catching an error while playing + */ +extern OPNMIDI_DECLSPEC int opn2_playFormat(struct OPN2_MIDIPlayer *device, int sampleCount, OPN2_UInt8 *left, OPN2_UInt8 *right, const struct OPNMIDI_AudioFormat *format); -/*Generate audio output from chip emulators without iteration of MIDI timers.*/ -extern int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampleCount, OPN2_UInt8 *left, OPN2_UInt8 *right, const struct OPNMIDI_AudioFormat *format); +/** + * @brief Generate PCM signed 16-bit stereo audio output without iteration of MIDI timers + * + * Use this function when you are using library as Real-Time MIDI synthesizer or with + * an external MIDI sequencer. You must to request the amount of samples which is equal + * to the delta between of MIDI event rows. One MIDI row is a group of MIDI events + * are having zero delta/delay between each other. When you are receiving events in + * real time, request the minimal possible delay value. + * + * Don't use count of frames, use instead count of samples. One frame is two samples. + * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! + * + * @param device Instance of the library + * @param sampleCount + * @param out Pointer to output with 16-bit stereo PCM output + * @return Count of given samples, otherwise, 0 or when catching an error while playing + */ +extern OPNMIDI_DECLSPEC int opn2_generate(struct OPN2_MIDIPlayer *device, int sampleCount, short *out); + +/** + * @brief Generate PCM stereo audio output in sample format declared by given context without iteration of MIDI timers + * + * Use this function when you are using library as Real-Time MIDI synthesizer or with + * an external MIDI sequencer. You must to request the amount of samples which is equal + * to the delta between of MIDI event rows. One MIDI row is a group of MIDI events + * are having zero delta/delay between each other. When you are receiving events in + * real time, request the minimal possible delay value. + * + * Don't use count of frames, use instead count of samples. One frame is two samples. + * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! + * + * @param device Instance of the library + * @param sampleCount + * @param left Left channel buffer output (Must be casted into bytes array) + * @param right Right channel buffer output (Must be casted into bytes array) + * @param format Destination PCM format format context + * @return Count of given samples, otherwise, 0 or when catching an error while playing + */ +extern OPNMIDI_DECLSPEC int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampleCount, OPN2_UInt8 *left, OPN2_UInt8 *right, const struct OPNMIDI_AudioFormat *format); /** * @brief Periodic tick handler. @@ -254,63 +786,291 @@ extern int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampleCount, * Use it for Hardware OPL3 mode or when you want to process events differently from opn2_play() function. * DON'T USE IT TOGETHER WITH opn2_play()!!! */ -extern double opn2_tickEvents(struct OPN2_MIDIPlayer *device, double seconds, double granuality); +extern OPNMIDI_DECLSPEC double opn2_tickEvents(struct OPN2_MIDIPlayer *device, double seconds, double granuality); -/*Returns 1 if music position has reached end*/ -extern int opn2_atEnd(struct OPN2_MIDIPlayer *device); +/** + * @brief Track options + */ +enum OPNMIDI_TrackOptions +{ + /*! Enabled track */ + OPNMIDI_TrackOption_On = 1, + /*! Disabled track */ + OPNMIDI_TrackOption_Off = 2, + /*! Solo track */ + OPNMIDI_TrackOption_Solo = 3, +}; -/**RealTime**/ - -/*Force Off all notes on all channels*/ -extern void opn2_panic(struct OPN2_MIDIPlayer *device); - -/*Reset states of all controllers on all MIDI channels*/ -extern void opn2_rt_resetState(struct OPN2_MIDIPlayer *device); - -/*Turn specific MIDI note ON*/ -extern int opn2_rt_noteOn(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 velocity); - -/*Turn specific MIDI note OFF*/ -extern void opn2_rt_noteOff(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note); - -/*Set note after-touch*/ -extern void opn2_rt_noteAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 atVal); -/*Set channel after-touch*/ -extern void opn2_rt_channelAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 atVal); - -/*Apply controller change*/ -extern void opn2_rt_controllerChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 type, OPN2_UInt8 value); - -/*Apply patch change*/ -extern void opn2_rt_patchChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 patch); - -/*Apply pitch bend change*/ -extern void opn2_rt_pitchBend(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt16 pitch); -/*Apply pitch bend change*/ -extern void opn2_rt_pitchBendML(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb, OPN2_UInt8 lsb); - -/*Change LSB of the bank*/ -extern void opn2_rt_bankChangeLSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 lsb); -/*Change MSB of the bank*/ -extern void opn2_rt_bankChangeMSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb); -/*Change bank by absolute signed value*/ -extern void opn2_rt_bankChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_SInt16 bank); +/** + * @brief Sets options on a track of the current sequence + * @param device Instance of the library + * @param trackNumber Identifier of the designated track. + * @return 0 on success, <0 when any error has occurred + */ +extern OPNMIDI_DECLSPEC int opn2_setTrackOptions(struct OPN2_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions); -/**Hooks**/ + +/* ======== Real-Time MIDI ======== */ + +/** + * @brief Force Off all notes on all channels + * @param device Instance of the library + */ +extern OPNMIDI_DECLSPEC void opn2_panic(struct OPN2_MIDIPlayer *device); + +/** + * @brief Reset states of all controllers on all MIDI channels + * @param device Instance of the library + */ +extern OPNMIDI_DECLSPEC void opn2_rt_resetState(struct OPN2_MIDIPlayer *device); + +/** + * @brief Turn specific MIDI note ON + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param note Note number to on [Between 0 and 127] + * @param velocity Velocity level [Between 0 and 127] + * @return 1 when note was successfully started, 0 when note was rejected by any reason. + */ +extern OPNMIDI_DECLSPEC int opn2_rt_noteOn(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 velocity); + +/** + * @brief Turn specific MIDI note OFF + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param note Note number to off [Between 0 and 127] + */ +extern OPNMIDI_DECLSPEC void opn2_rt_noteOff(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note); + +/** + * @brief Set note after-touch + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param note Note number to affect by aftertouch event [Between 0 and 127] + * @param atVal After-Touch value [Between 0 and 127] + */ +extern OPNMIDI_DECLSPEC void opn2_rt_noteAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 atVal); + +/** + * @brief Set channel after-touch + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param atVal After-Touch level [Between 0 and 127] + */ +extern OPNMIDI_DECLSPEC void opn2_rt_channelAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 atVal); + +/** + * @brief Apply controller change + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param type Type of the controller [Between 0 and 255] + * @param value Value of the controller event [Between 0 and 127] + */ +extern OPNMIDI_DECLSPEC void opn2_rt_controllerChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 type, OPN2_UInt8 value); + +/** + * @brief Apply patch change + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param patch Patch number [Between 0 and 127] + */ +extern OPNMIDI_DECLSPEC void opn2_rt_patchChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 patch); + +/** + * @brief Apply pitch bend change + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param pitch 24-bit pitch bend value + */ +extern OPNMIDI_DECLSPEC void opn2_rt_pitchBend(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt16 pitch); + +/** + * @brief Apply pitch bend change + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param msb MSB part of 24-bit pitch bend value + * @param lsb LSB part of 24-bit pitch bend value + */ +extern OPNMIDI_DECLSPEC void opn2_rt_pitchBendML(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb, OPN2_UInt8 lsb); + +/** + * @brief Change LSB of the bank number (Alias to CC-32 event) + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param lsb LSB value of the MIDI bank number + */ +extern OPNMIDI_DECLSPEC void opn2_rt_bankChangeLSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 lsb); + +/** + * @brief Change MSB of the bank (Alias to CC-0 event) + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param msb MSB value of the MIDI bank number + */ +extern OPNMIDI_DECLSPEC void opn2_rt_bankChangeMSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb); + +/** + * @brief Change bank by absolute signed value + * @param device Instance of the library + * @param channel Target MIDI channel [Between 0 and 16] + * @param bank Bank number as concoctated signed 16-bit value of MSB and LSB parts. + */ +extern OPNMIDI_DECLSPEC void opn2_rt_bankChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_SInt16 bank); + +/** + * @brief Perform a system exclusive message + * @param device Instance of the library + * @param msg Raw SysEx message buffer (must begin with 0xF0 and end with 0xF7) + * @param size Size of given SysEx message buffer + * @return 1 when SysEx message was successfully processed, 0 when SysEx message was rejected by any reason + */ +extern OPNMIDI_DECLSPEC int opn2_rt_systemExclusive(struct OPN2_MIDIPlayer *device, const OPN2_UInt8 *msg, size_t size); + +/* ======== Hooks and debugging ======== */ + +/** + * @brief Raw event callback + * @param userdata Pointer to user data (usually, context of someting) + * @param type MIDI event type + * @param subtype MIDI event sub-type (special events only) + * @param channel MIDI channel + * @param data Raw event data + * @param len Length of event data + */ typedef void (*OPN2_RawEventHook)(void *userdata, OPN2_UInt8 type, OPN2_UInt8 subtype, OPN2_UInt8 channel, const OPN2_UInt8 *data, size_t len); +/** + * @brief Note on/off callback + * @param userdata Pointer to user data (usually, context of someting) + * @param adlchn Chip channel where note was played + * @param note Note number [between 0 and 127] + * @param pressure Velocity level, or -1 when it's note off event + * @param bend Pitch bend offset value + */ typedef void (*OPN2_NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend); + +/** + * @brief Debug messages callback + * @param userdata Pointer to user data (usually, context of someting) + * @param fmt Format strign output (in context of `printf()` standard function) + */ typedef void (*OPN2_DebugMessageHook)(void *userdata, const char *fmt, ...); -/* Set raw MIDI event hook */ -extern void opn2_setRawEventHook(struct OPN2_MIDIPlayer *device, OPN2_RawEventHook rawEventHook, void *userData); +/** + * @brief Set raw MIDI event hook + * @param device Instance of the library + * @param rawEventHook Pointer to the callback function which will be called on every MIDI event + * @param userData Pointer to user data which will be passed through the callback. + */ +extern OPNMIDI_DECLSPEC void opn2_setRawEventHook(struct OPN2_MIDIPlayer *device, OPN2_RawEventHook rawEventHook, void *userData); -/* Set note hook */ -extern void opn2_setNoteHook(struct OPN2_MIDIPlayer *device, OPN2_NoteHook noteHook, void *userData); +/** + * @brief Set note hook + * @param device Instance of the library + * @param noteHook Pointer to the callback function which will be called on every noteOn MIDI event + * @param userData Pointer to user data which will be passed through the callback. + */ +extern OPNMIDI_DECLSPEC void opn2_setNoteHook(struct OPN2_MIDIPlayer *device, OPN2_NoteHook noteHook, void *userData); -/* Set debug message hook */ -extern void opn2_setDebugMessageHook(struct OPN2_MIDIPlayer *device, OPN2_DebugMessageHook debugMessageHook, void *userData); +/** + * @brief Set debug message hook + * @param device Instance of the library + * @param debugMessageHook Pointer to the callback function which will be called on every debug message + * @param userData Pointer to user data which will be passed through the callback. + */ +extern OPNMIDI_DECLSPEC void opn2_setDebugMessageHook(struct OPN2_MIDIPlayer *device, OPN2_DebugMessageHook debugMessageHook, void *userData); + + +/** + * @brief Get a textual description of the channel state. For display only. + * @param device Instance of the library + * @param text Destination char buffer for channel usage state. Every entry is assigned to the chip channel. + * @param attr Destination char buffer for additional attributes like MIDI channel number that uses this chip channel. + * @param size Size of given buffers (both text and attr are must have same size!) + * @return 0 on success, <0 when any error has occurred + * + * Every character in the `text` buffer means the type of usage: + * ``` + * `-` - channel is unused (free) + * `+` - channel is used by regular voice + * `@` - channel is used to play automatic arpeggio on chip channels overflow + * ``` + * + * The `attr` field receives the MIDI channel from which the chip channel is used. + * To get the valid MIDI channel you will need to apply the & 0x0F mask to every value. + */ +extern OPNMIDI_DECLSPEC int opn2_describeChannels(struct OPN2_MIDIPlayer *device, char *text, char *attr, size_t size); + + + + +/* ======== Instrument structures ======== */ + +/** + * @brief Version of the instrument data format + */ +enum +{ + OPNMIDI_InstrumentVersion = 0 +}; + +/** + * @brief Instrument flags + */ +typedef enum OPN2_InstrumentFlags +{ + OPNMIDI_Ins_Pseudo8op = 0x01, /*Reserved for future use, not implemented yet*/ + OPNMIDI_Ins_IsBlank = 0x02 +} OPN2_InstrumentFlags; + +/** + * @brief Operator structure, part of Instrument structure + */ +typedef struct OPN2_Operator +{ + /* Detune and frequency multiplication register data */ + OPN2_UInt8 dtfm_30; + /* Total level register data */ + OPN2_UInt8 level_40; + /* Rate scale and attack register data */ + OPN2_UInt8 rsatk_50; + /* Amplitude modulation enable and Decay-1 register data */ + OPN2_UInt8 amdecay1_60; + /* Decay-2 register data */ + OPN2_UInt8 decay2_70; + /* Sustain and Release register data */ + OPN2_UInt8 susrel_80; + /* SSG-EG register data */ + OPN2_UInt8 ssgeg_90; +} OPN2_Operator; + +/** + * @brief Instrument structure + */ +typedef struct OPN2_Instrument +{ + /*! Version of the instrument object */ + int version; + /* MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */ + OPN2_SInt16 note_offset; + /* Reserved */ + OPN2_SInt8 midi_velocity_offset; + /* Percussion MIDI base tone number at which this drum will be played */ + OPN2_UInt8 percussion_key_number; + /* Instrument flags */ + OPN2_UInt8 inst_flags; + /* Feedback and Algorithm register data */ + OPN2_UInt8 fbalg; + /* LFO Sensitivity register data */ + OPN2_UInt8 lfosens; + /* Operators register data */ + OPN2_Operator operators[4]; + /* Millisecond delay of sounding while key is on */ + OPN2_UInt16 delay_on_ms; + /* Millisecond delay of sounding after key off */ + OPN2_UInt16 delay_off_ms; +} OPN2_Instrument; #ifdef __cplusplus } diff --git a/src/sound/opnmidi/opnmidi_bankmap.h b/src/sound/opnmidi/opnmidi_bankmap.h index eb05566bc..98293b899 100644 --- a/src/sound/opnmidi/opnmidi_bankmap.h +++ b/src/sound/opnmidi/opnmidi_bankmap.h @@ -40,7 +40,7 @@ template class BasicBankMap { public: - typedef uint16_t key_type; /* the bank identifier */ + typedef size_t key_type; /* the bank identifier */ typedef T mapped_type; typedef std::pair value_type; diff --git a/src/sound/opnmidi/opnmidi_cvt.hpp b/src/sound/opnmidi/opnmidi_cvt.hpp new file mode 100644 index 000000000..b565b9bc4 --- /dev/null +++ b/src/sound/opnmidi/opnmidi_cvt.hpp @@ -0,0 +1,82 @@ +/* + * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation + * + * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma + * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov + * + * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: + * http://iki.fi/bisqwit/source/adlmidi.html + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "opnbank.h" + +template +static void cvt_generic_to_FMIns(opnInstMeta2 &ins, const WOPNI &in) +{ + ins.tone = in.percussion_key_number; + ins.flags = in.inst_flags; + /* Junk, delete later */ + ins.fine_tune = 0.0; + /* Junk, delete later */ + + ins.opn[0].fbalg = in.fbalg; + ins.opn[0].lfosens = in.lfosens; + ins.opn[0].finetune = in.note_offset; + ins.midi_velocity_offset = in.midi_velocity_offset; + + for(size_t op = 0; op < 4; op++) + { + ins.opn[0].OPS[op].data[0] = in.operators[op].dtfm_30; + ins.opn[0].OPS[op].data[1] = in.operators[op].level_40; + ins.opn[0].OPS[op].data[2] = in.operators[op].rsatk_50; + ins.opn[0].OPS[op].data[3] = in.operators[op].amdecay1_60; + ins.opn[0].OPS[op].data[4] = in.operators[op].decay2_70; + ins.opn[0].OPS[op].data[5] = in.operators[op].susrel_80; + ins.opn[0].OPS[op].data[6] = in.operators[op].ssgeg_90; + } + + ins.opn[1] = ins.opn[0]; + + ins.ms_sound_kon = in.delay_on_ms; + ins.ms_sound_koff = in.delay_off_ms; +} + +template +static void cvt_FMIns_to_generic(WOPNI &ins, const opnInstMeta2 &in) +{ + ins.percussion_key_number = in.tone; + ins.inst_flags = in.flags; + + ins.fbalg = in.opn[0].fbalg; + ins.lfosens = in.opn[0].lfosens; + ins.note_offset = in.opn[0].finetune; + + ins.midi_velocity_offset = in.midi_velocity_offset; + + for(size_t op = 0; op < 4; op++) + { + ins.operators[op].dtfm_30 = in.opn[0].OPS[op].data[0]; + ins.operators[op].level_40 = in.opn[0].OPS[op].data[1]; + ins.operators[op].rsatk_50 = in.opn[0].OPS[op].data[2]; + ins.operators[op].amdecay1_60 = in.opn[0].OPS[op].data[3]; + ins.operators[op].decay2_70 = in.opn[0].OPS[op].data[4]; + ins.operators[op].susrel_80 = in.opn[0].OPS[op].data[5]; + ins.operators[op].ssgeg_90 = in.opn[0].OPS[op].data[6]; + } + + ins.delay_on_ms = in.ms_sound_kon; + ins.delay_off_ms = in.ms_sound_koff; +} diff --git a/src/sound/opnmidi/opnmidi_load.cpp b/src/sound/opnmidi/opnmidi_load.cpp index c52b8093c..1fd8a3332 100644 --- a/src/sound/opnmidi/opnmidi_load.cpp +++ b/src/sound/opnmidi/opnmidi_load.cpp @@ -22,542 +22,203 @@ */ #include "opnmidi_private.hpp" - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER -# ifndef OPNMIDI_DISABLE_MUS_SUPPORT -# include "opnmidi_mus2mid.h" -# endif -# ifndef OPNMIDI_DISABLE_XMI_SUPPORT -# include "opnmidi_xmi2mid.h" -# endif -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER - -uint64_t OPNMIDIplay::ReadBEint(const void *buffer, size_t nbytes) -{ - uint64_t result = 0; - const unsigned char *data = reinterpret_cast(buffer); - - for(unsigned n = 0; n < nbytes; ++n) - result = (result << 8) + data[n]; - - return result; -} - -uint64_t OPNMIDIplay::ReadLEint(const void *buffer, size_t nbytes) -{ - uint64_t result = 0; - const unsigned char *data = reinterpret_cast(buffer); - - for(unsigned n = 0; n < nbytes; ++n) - result = result + static_cast(data[n] << (n * 8)); - - return result; -} - -//uint64_t OPNMIDIplay::ReadVarLenEx(size_t tk, bool &ok) -//{ -// uint64_t result = 0; -// ok = false; - -// for(;;) -// { -// if(tk >= TrackData.size()) -// return 1; - -// if(tk >= CurrentPosition.track.size()) -// return 2; - -// size_t ptr = CurrentPosition.track[tk].ptr; - -// if(ptr >= TrackData[tk].size()) -// return 3; - -// unsigned char byte = TrackData[tk][CurrentPosition.track[tk].ptr++]; -// result = (result << 7) + (byte & 0x7F); - -// if(!(byte & 0x80)) break; -// } - -// ok = true; -// return result; -//} +#include "opnmidi_cvt.hpp" +#include "wopn/wopn_file.h" bool OPNMIDIplay::LoadBank(const std::string &filename) { - fileReader file; + FileAndMemReader file; file.openFile(filename.c_str()); return LoadBank(file); } bool OPNMIDIplay::LoadBank(const void *data, size_t size) { - fileReader file; + FileAndMemReader file; file.openData(data, (size_t)size); return LoadBank(file); } -size_t readU16BE(OPNMIDIplay::fileReader &fr, uint16_t &out) +void cvt_OPNI_to_FMIns(opnInstMeta2 &ins, const OPN2_Instrument &in) { - uint8_t arr[2]; - size_t ret = fr.read(arr, 1, 2); - out = arr[1]; - out |= ((arr[0] << 8) & 0xFF00); - return ret; + return cvt_generic_to_FMIns(ins, in); } -size_t readS16BE(OPNMIDIplay::fileReader &fr, int16_t &out) +void cvt_FMIns_to_OPNI(OPN2_Instrument &ins, const opnInstMeta2 &in) { - uint8_t arr[2]; - size_t ret = fr.read(arr, 1, 2); - out = *reinterpret_cast(&arr[0]); - out *= 1 << 8; - out |= arr[1]; - return ret; + cvt_FMIns_to_generic(ins, in); } -int16_t toSint16BE(uint8_t *arr) -{ - int16_t num = *reinterpret_cast(&arr[0]); - num *= 1 << 8; - num |= arr[1]; - return num; -} - -static uint16_t toUint16LE(const uint8_t *arr) -{ - uint16_t num = arr[0]; - num |= ((arr[1] << 8) & 0xFF00); - return num; -} - -static uint16_t toUint16BE(const uint8_t *arr) -{ - uint16_t num = arr[1]; - num |= ((arr[0] << 8) & 0xFF00); - return num; -} - - -static const char *wopn2_magic1 = "WOPN2-BANK\0"; -static const char *wopn2_magic2 = "WOPN2-B2NK\0"; - -#define WOPL_INST_SIZE_V1 65 -#define WOPL_INST_SIZE_V2 69 - -static const uint16_t latest_version = 2; - -bool OPNMIDIplay::LoadBank(OPNMIDIplay::fileReader &fr) +bool OPNMIDIplay::LoadBank(FileAndMemReader &fr) { + int err = 0; + WOPNFile *wopn = NULL; + char *raw_file_data = NULL; size_t fsize; - ADL_UNUSED(fsize); if(!fr.isValid()) { - errorStringOut = "Can't load bank file: Invalid data stream!"; + errorStringOut = "Custom bank: Invalid data stream!"; return false; } - char magic[32]; - std::memset(magic, 0, 32); - uint16_t version = 1; - - uint16_t count_melodic_banks = 1; - uint16_t count_percussive_banks = 1; - - if(fr.read(magic, 1, 11) != 11) + // Read complete bank file into the memory + fsize = fr.fileSize(); + fr.seek(0, FileAndMemReader::SET); + // Allocate necessary memory block + raw_file_data = (char*)malloc(fsize); + if(!raw_file_data) { - errorStringOut = "Can't load bank file: Can't read magic number!"; + errorStringOut = "Custom bank: Out of memory before of read!"; return false; } + fr.read(raw_file_data, 1, fsize); - bool is1 = std::strncmp(magic, wopn2_magic1, 11) == 0; - bool is2 = std::strncmp(magic, wopn2_magic2, 11) == 0; + // Parse bank file from the memory + wopn = WOPN_LoadBankFromMem((void*)raw_file_data, fsize, &err); + //Free the buffer no more needed + free(raw_file_data); - if(!is1 && !is2) + // Check for any erros + if(!wopn) { - errorStringOut = "Can't load bank file: Invalid magic number!"; - return false; - } - - if(is2) - { - uint8_t ver[2]; - if(fr.read(ver, 1, 2) != 2) + switch(err) { - errorStringOut = "Can't load bank file: Can't read version number!"; + case WOPN_ERR_BAD_MAGIC: + errorStringOut = "Custom bank: Invalid magic!"; return false; - } - version = toUint16LE(ver); - if(version < 2 || version > latest_version) - { - errorStringOut = "Can't load bank file: unsupported WOPN version!"; + case WOPN_ERR_UNEXPECTED_ENDING: + errorStringOut = "Custom bank: Unexpected ending!"; + return false; + case WOPN_ERR_INVALID_BANKS_COUNT: + errorStringOut = "Custom bank: Invalid banks count!"; + return false; + case WOPN_ERR_NEWER_VERSION: + errorStringOut = "Custom bank: Version is newer than supported by this library!"; + return false; + case WOPN_ERR_OUT_OF_MEMORY: + errorStringOut = "Custom bank: Out of memory!"; + return false; + default: + errorStringOut = "Custom bank: Unknown error!"; return false; } } - opn.cleanInstrumentBanks(); - if((readU16BE(fr, count_melodic_banks) != 2) || (readU16BE(fr, count_percussive_banks) != 2)) + m_synth.m_insBankSetup.volumeModel = wopn->volume_model; + m_synth.m_insBankSetup.lfoEnable = (wopn->lfo_freq & 8) != 0; + m_synth.m_insBankSetup.lfoFrequency = wopn->lfo_freq & 7; + m_setup.VolumeModel = OPNMIDI_VolumeModel_AUTO; + m_setup.lfoEnable = -1; + m_setup.lfoFrequency = -1; + + m_synth.m_insBanks.clear(); + + uint16_t slots_counts[2] = {wopn->banks_count_melodic, wopn->banks_count_percussion}; + WOPNBank *slots_src_ins[2] = { wopn->banks_melodic, wopn->banks_percussive }; + + for(size_t ss = 0; ss < 2; ss++) { - errorStringOut = "Can't load bank file: Can't read count of banks!"; - return false; - } - - if((count_melodic_banks < 1) || (count_percussive_banks < 1)) - { - errorStringOut = "Custom bank: Too few banks in this file!"; - return false; - } - - if(fr.read(&opn.regLFO, 1, 1) != 1) - { - errorStringOut = "Can't load bank file: Can't read LFO registry state!"; - return false; - } - - opn.cleanInstrumentBanks(); - - std::vector banks; - banks.reserve(count_melodic_banks + count_percussive_banks); - - if(version >= 2)//Read bank meta-entries - { - for(uint16_t i = 0; i < count_melodic_banks; i++) + for(size_t i = 0; i < slots_counts[ss]; i++) { - uint8_t bank_meta[34]; - if(fr.read(bank_meta, 1, 34) != 34) + size_t bankno = (slots_src_ins[ss][i].bank_midi_msb * 256) + + (slots_src_ins[ss][i].bank_midi_lsb) + + (ss ? size_t(OPN2::PercussionTag) : 0); + OPN2::Bank &bank = m_synth.m_insBanks[bankno]; + for(int j = 0; j < 128; j++) { - opn.cleanInstrumentBanks(); - errorStringOut = "Custom bank: Fail to read melodic bank meta-data!"; - return false; + opnInstMeta2 &ins = bank.ins[j]; + std::memset(&ins, 0, sizeof(opnInstMeta2)); + WOPNInstrument &inIns = slots_src_ins[ss][i].ins[j]; + cvt_generic_to_FMIns(ins, inIns); } - uint16_t bankno = uint16_t(bank_meta[33]) * 256 + uint16_t(bank_meta[32]); - OPN2::Bank &bank = opn.dynamic_banks[bankno]; - //strncpy(bank.name, char_p(bank_meta), 32); - banks.push_back(&bank); } - - for(uint16_t i = 0; i < count_percussive_banks; i++) - { - uint8_t bank_meta[34]; - if(fr.read(bank_meta, 1, 34) != 34) - { - opn.cleanInstrumentBanks(); - errorStringOut = "Custom bank: Fail to read percussion bank meta-data!"; - return false; - } - uint16_t bankno = uint16_t(bank_meta[33]) * 256 + uint16_t(bank_meta[32]) + OPN2::PercussionTag; - OPN2::Bank &bank = opn.dynamic_banks[bankno]; - //strncpy(bank.name, char_p(bank_meta), 32); - banks.push_back(&bank); - } - } - - size_t total = 128 * opn.dynamic_banks.size(); - - for(size_t i = 0; i < total; i++) - { - opnInstMeta2 &meta = banks[i / 128]->ins[i % 128]; - opnInstData &data = meta.opn[0]; - uint8_t idata[WOPL_INST_SIZE_V2]; - - size_t readSize = version >= 2 ? WOPL_INST_SIZE_V2 : WOPL_INST_SIZE_V1; - if(fr.read(idata, 1, readSize) != readSize) - { - opn.cleanInstrumentBanks(); - errorStringOut = "Can't load bank file: Failed to read instrument data"; - return false; - } - data.finetune = toSint16BE(idata + 32); - //Percussion instrument note number or a "fixed note sound" - meta.tone = idata[34]; - data.fbalg = idata[35]; - data.lfosens = idata[36]; - for(size_t op = 0; op < 4; op++) - { - size_t off = 37 + op * 7; - std::memcpy(data.OPS[op].data, idata + off, 7); - } - - meta.flags = 0; - if(version >= 2) - { - meta.ms_sound_kon = toUint16BE(idata + 65); - meta.ms_sound_koff = toUint16BE(idata + 67); - if((meta.ms_sound_kon == 0) && (meta.ms_sound_koff == 0)) - meta.flags |= opnInstMeta::Flag_NoSound; - } - else - { - meta.ms_sound_kon = 1000; - meta.ms_sound_koff = 500; - } - - meta.opn[1] = meta.opn[0]; - - /* Junk, delete later */ - meta.fine_tune = 0.0; - /* Junk, delete later */ } applySetup(); + WOPN_Free(wopn); + return true; } #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER + +bool OPNMIDIplay::LoadMIDI_pre() +{ + if(m_synth.m_insBanks.empty()) + { + errorStringOut = "Bank is not set! Please load any instruments bank by using of adl_openBankFile() or adl_openBankData() functions!"; + return false; + } + + /**** Set all properties BEFORE starting of actial file reading! ****/ + resetMIDI(); + applySetup(); + + return true; +} + +bool OPNMIDIplay::LoadMIDI_post() +{ + MidiSequencer::FileFormat format = m_sequencer.getFormat(); + if(format == MidiSequencer::Format_CMF) + { + errorStringOut = "OPNMIDI doesn't supports CMF, use ADLMIDI to play this file!"; + /* As joke, why not to try implemented the converter of patches from OPL3 into OPN2? */ + return false; + } + else if(format == MidiSequencer::Format_RSXX) + { + m_synth.m_musicMode = OPN2::MODE_RSXX; + m_synth.m_volumeScale = OPN2::VOLUME_Generic; + m_synth.m_numChips = 2; + } + else if(format == MidiSequencer::Format_IMF) + { + errorStringOut = "OPNMIDI doesn't supports IMF, use ADLMIDI to play this file!"; + /* Same as for CMF */ + return false; + } + + m_setup.tick_skip_samples_delay = 0; + m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); // Reset OPN2 chip + m_chipChannels.clear(); + m_chipChannels.resize(m_synth.m_numChannels); + + return true; +} + + bool OPNMIDIplay::LoadMIDI(const std::string &filename) { - fileReader file; + FileAndMemReader file; file.openFile(filename.c_str()); - if(!LoadMIDI(file)) + if(!LoadMIDI_pre()) + return false; + if(!m_sequencer.loadMIDI(file)) + { + errorStringOut = m_sequencer.getErrorString(); + return false; + } + if(!LoadMIDI_post()) return false; return true; } bool OPNMIDIplay::LoadMIDI(const void *data, size_t size) { - fileReader file; + FileAndMemReader file; file.openData(data, size); - return LoadMIDI(file); -} - -bool OPNMIDIplay::LoadMIDI(OPNMIDIplay::fileReader &fr) -{ - size_t fsize; - ADL_UNUSED(fsize); - //! Temp buffer for conversion - AdlMIDI_CPtr cvt_buf; - errorString.clear(); - - if(opn.dynamic_banks.empty()) + if(!LoadMIDI_pre()) + return false; + if(!m_sequencer.loadMIDI(file)) { - errorStringOut = "Bank is not set! Please load any instruments bank by using of adl_openBankFile() or adl_openBankData() functions!"; + errorStringOut = m_sequencer.getErrorString(); return false; } - - if(!fr.isValid()) - { - errorStringOut = "Invalid data stream!\n"; - #ifndef _WIN32 - errorStringOut += std::strerror(errno); - #endif + if(!LoadMIDI_post()) return false; - } - - /**** Set all properties BEFORE starting of actial file reading! ****/ - applySetup(); - - atEnd = false; - loopStart = true; - invalidLoop = false; - - bool is_GMF = false; // GMD/MUS files (ScummVM) - bool is_RSXX = false; // RSXX, such as Cartooners - - const size_t HeaderSize = 4 + 4 + 2 + 2 + 2; // 14 - char HeaderBuf[HeaderSize] = ""; - size_t DeltaTicks = 192, TrackCount = 1; - -riffskip: - fsize = fr.read(HeaderBuf, 1, HeaderSize); - - if(std::memcmp(HeaderBuf, "RIFF", 4) == 0) - { - fr.seek(6l, SEEK_CUR); - goto riffskip; - } - - if(std::memcmp(HeaderBuf, "GMF\x1", 4) == 0) - { - // GMD/MUS files (ScummVM) - fr.seek(7 - static_cast(HeaderSize), SEEK_CUR); - is_GMF = true; - } - - #ifndef OPNMIDI_DISABLE_MUS_SUPPORT - else if(std::memcmp(HeaderBuf, "MUS\x1A", 4) == 0) - { - // MUS/DMX files (Doom) - fr.seek(0, SEEK_END); - size_t mus_len = fr.tell(); - fr.seek(0, SEEK_SET); - uint8_t *mus = (uint8_t *)malloc(mus_len); - if(!mus) - { - errorStringOut = "Out of memory!"; - return false; - } - fr.read(mus, 1, mus_len); - //Close source stream - fr.close(); - - uint8_t *mid = NULL; - uint32_t mid_len = 0; - int m2mret = OpnMidi_mus2midi(mus, static_cast(mus_len), - &mid, &mid_len, 0); - if(mus) free(mus); - if(m2mret < 0) - { - errorStringOut = "Invalid MUS/DMX data format!"; - return false; - } - cvt_buf.reset(mid); - //Open converted MIDI file - fr.openData(mid, static_cast(mid_len)); - //Re-Read header again! - goto riffskip; - } - #endif //OPNMIDI_DISABLE_MUS_SUPPORT - - #ifndef OPNMIDI_DISABLE_XMI_SUPPORT - else if(std::memcmp(HeaderBuf, "FORM", 4) == 0) - { - if(std::memcmp(HeaderBuf + 8, "XDIR", 4) != 0) - { - fr.close(); - errorStringOut = fr._fileName + ": Invalid format\n"; - return false; - } - - fr.seek(0, SEEK_END); - size_t mus_len = fr.tell(); - fr.seek(0, SEEK_SET); - uint8_t *mus = (uint8_t*)malloc(mus_len); - if(!mus) - { - errorStringOut = "Out of memory!"; - return false; - } - fr.read(mus, 1, mus_len); - //Close source stream - fr.close(); - - uint8_t *mid = NULL; - uint32_t mid_len = 0; - int m2mret = OpnMidi_xmi2midi(mus, static_cast(mus_len), - &mid, &mid_len, XMIDI_CONVERT_NOCONVERSION); - if(mus) free(mus); - if(m2mret < 0) - { - errorStringOut = "Invalid XMI data format!"; - return false; - } - cvt_buf.reset(mid); - //Open converted MIDI file - fr.openData(mid, static_cast(mid_len)); - //Re-Read header again! - goto riffskip; - } - #endif //OPNMIDI_DISABLE_XMI_SUPPORT - - else - { - // Try to identify RSXX format - if(HeaderBuf[0] == 0x7D) - { - fr.seek(0x6D, SEEK_SET); - fr.read(HeaderBuf, 6, 1); - if(std::memcmp(HeaderBuf, "rsxx}u", 6) == 0) - { - is_RSXX = true; - fr.seek(0x7D, SEEK_SET); - TrackCount = 1; - DeltaTicks = 60; - //opl.CartoonersVolumes = true; - opn.m_musicMode = OPN2::MODE_RSXX; - opn.m_volumeScale = OPN2::VOLUME_CMF; - } - } - - if(!is_RSXX) - { - if(std::memcmp(HeaderBuf, "MThd\0\0\0\6", 8) != 0) - { - fr.close(); - errorStringOut = fr._fileName + ": Invalid format, Header signature is unknown!\n"; - return false; - } - - /*size_t Fmt = ReadBEint(HeaderBuf + 8, 2);*/ - TrackCount = (size_t)ReadBEint(HeaderBuf + 10, 2); - DeltaTicks = (size_t)ReadBEint(HeaderBuf + 12, 2); - } - } - - TrackData.clear(); - TrackData.resize(TrackCount, std::vector()); - InvDeltaTicks = fraction(1, 1000000l * static_cast(DeltaTicks)); - Tempo = fraction(1, static_cast(DeltaTicks) * 2); - static const unsigned char EndTag[4] = {0xFF, 0x2F, 0x00, 0x00}; - size_t totalGotten = 0; - - for(size_t tk = 0; tk < TrackCount; ++tk) - { - // Read track header - size_t TrackLength; - { - if(is_GMF || is_RSXX) // Take the rest of the file - { - size_t pos = fr.tell(); - fr.seek(0, SEEK_END); - TrackLength = fr.tell() - pos; - fr.seek(static_cast(pos), SEEK_SET); - } - else - { - fsize = fr.read(HeaderBuf, 1, 8); - if(std::memcmp(HeaderBuf, "MTrk", 4) != 0) - { - fr.close(); - errorStringOut = fr._fileName + ": Invalid format, MTrk signature is not found!\n"; - return false; - } - TrackLength = (size_t)ReadBEint(HeaderBuf + 4, 4); - } - - // Read track data - TrackData[tk].resize(TrackLength); - fsize = fr.read(&TrackData[tk][0], 1, TrackLength); - totalGotten += fsize; - - if(is_GMF/*|| is_MUS*/) // Note: CMF does include the track end tag. - TrackData[tk].insert(TrackData[tk].end(), EndTag + 0, EndTag + 4); - if(is_RSXX)//Finalize raw track data with a zero - TrackData[tk].push_back(0); - - //bool ok = false; - //// Read next event time - //uint64_t tkDelay = ReadVarLenEx(tk, ok); - //if(ok) - // CurrentPosition.track[tk].delay = tkDelay; - //else - //{ - // std::stringstream msg; - // msg << fr._fileName << ": invalid variable length in the track " << tk << "! (error code " << tkDelay << ")"; - // OPN2MIDI_ErrorString = msg.str(); - // return false; - //} - } - } - - for(size_t tk = 0; tk < TrackCount; ++tk) - totalGotten += TrackData[tk].size(); - - if(totalGotten == 0) - { - errorStringOut = fr._fileName + ": Empty track data"; - return false; - } - - //Build new MIDI events table - if(!buildTrackData()) - { - errorStringOut = fr._fileName + ": MIDI data parsing error has occouped!\n" + errorString; - return false; - } - - opn.Reset(m_setup.emulator, m_setup.PCM_RATE); // Reset OPN2 chip - ch.clear(); - ch.resize(opn.NumChannels); return true; } + #endif //OPNMIDI_DISABLE_MIDI_SEQUENCER diff --git a/src/sound/opnmidi/opnmidi_midiplay.cpp b/src/sound/opnmidi/opnmidi_midiplay.cpp index 5a93bb36e..6e9f3bc0e 100644 --- a/src/sound/opnmidi/opnmidi_midiplay.cpp +++ b/src/sound/opnmidi/opnmidi_midiplay.cpp @@ -25,7 +25,7 @@ // Mapping from MIDI volume level to OPL level value. -static const uint32_t DMX_volume_mapping_table[] = +static const uint_fast32_t DMX_volume_mapping_table[128] = { 0, 1, 3, 5, 6, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, @@ -43,26 +43,9 @@ static const uint32_t DMX_volume_mapping_table[] = 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 123, 124, 124, 125, 125, 126, 126, 127, 127, - //Protection entries to avoid crash if value more than 127 - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, }; -static const uint8_t W9X_volume_mapping_table[32] = +static const uint_fast32_t W9X_volume_mapping_table[32] = { 63, 63, 40, 36, 32, 28, 23, 21, 19, 17, 15, 14, 13, 12, 11, 10, @@ -70,609 +53,46 @@ static const uint8_t W9X_volume_mapping_table[32] = 3, 3, 2, 2, 1, 1, 0, 0 }; +enum { MasterVolumeDefault = 127 }; + inline bool isXgPercChannel(uint8_t msb, uint8_t lsb) { return (msb == 0x7E || msb == 0x7F) && (lsb == 0); } -void OPNMIDIplay::OpnChannel::AddAge(int64_t ms) +void OPNMIDIplay::OpnChannel::addAge(int64_t us) { - const int64_t neg = static_cast(-0x1FFFFFFFl); + const int64_t neg = 1000 * static_cast(-0x1FFFFFFFl); if(users_empty()) - koff_time_until_neglible = - std::max(int64_t(koff_time_until_neglible - ms), neg); + { + koff_time_until_neglible_us = std::max(koff_time_until_neglible_us - us, neg); + if(koff_time_until_neglible_us < 0) + koff_time_until_neglible_us = 0; + } else { - koff_time_until_neglible = 0; - + koff_time_until_neglible_us = 0; for(LocationData *i = users_first; i; i = i->next) { if(!i->fixed_sustain) - i->kon_time_until_neglible = std::max(i->kon_time_until_neglible - ms, neg); - i->vibdelay += ms; + i->kon_time_until_neglible_us = std::max(i->kon_time_until_neglible_us - us, neg); + i->vibdelay_us += us; } } } -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - -OPNMIDIplay::MidiEvent::MidiEvent() : - type(T_UNKNOWN), - subtype(T_UNKNOWN), - channel(0), - isValid(1), - absPosition(0) -{} - - -OPNMIDIplay::MidiTrackRow::MidiTrackRow() : - time(0.0), - delay(0), - absPos(0), - timeDelay(0.0) -{} - -void OPNMIDIplay::MidiTrackRow::reset() -{ - time = 0.0; - delay = 0; - absPos = 0; - timeDelay = 0.0; - events.clear(); -} - -void OPNMIDIplay::MidiTrackRow::sortEvents(bool *noteStates) -{ - typedef std::vector EvtArr; - EvtArr metas; - EvtArr noteOffs; - EvtArr controllers; - EvtArr anyOther; - - metas.reserve(events.size()); - noteOffs.reserve(events.size()); - controllers.reserve(events.size()); - anyOther.reserve(events.size()); - - for(size_t i = 0; i < events.size(); i++) - { - if(events[i].type == MidiEvent::T_NOTEOFF) - noteOffs.push_back(events[i]); - else if((events[i].type == MidiEvent::T_CTRLCHANGE) - || (events[i].type == MidiEvent::T_PATCHCHANGE) - || (events[i].type == MidiEvent::T_WHEEL) - || (events[i].type == MidiEvent::T_CHANAFTTOUCH)) - { - controllers.push_back(events[i]); - } - else if((events[i].type == MidiEvent::T_SPECIAL) && (events[i].subtype == MidiEvent::ST_MARKER)) - metas.push_back(events[i]); - else - anyOther.push_back(events[i]); - } - - /* - * If Note-Off and it's Note-On is on the same row - move this damned note off down! - */ - if(noteStates) - { - std::set markAsOn; - for(size_t i = 0; i < anyOther.size(); i++) - { - const MidiEvent e = anyOther[i]; - if(e.type == MidiEvent::T_NOTEON) - { - const size_t note_i = (e.channel * 255) + (e.data[0] & 0x7F); - //Check, was previously note is on or off - bool wasOn = noteStates[note_i]; - markAsOn.insert(note_i); - // Detect zero-length notes are following previously pressed note - int noteOffsOnSameNote = 0; - for(EvtArr::iterator j = noteOffs.begin(); j != noteOffs.end();) - { - //If note was off, and note-off on same row with note-on - move it down! - if( - ((*j).channel == e.channel) && - ((*j).data[0] == e.data[0]) - ) - { - //If note is already off OR more than one note-off on same row and same note - if(!wasOn || (noteOffsOnSameNote != 0)) - { - anyOther.push_back(*j); - j = noteOffs.erase(j); - markAsOn.erase(note_i); - continue; - } else { - //When same row has many note-offs on same row - //that means a zero-length note follows previous note - //it must be shuted down - noteOffsOnSameNote++; - } - } - j++; - } - } - } - - //Mark other notes as released - for(EvtArr::iterator j = noteOffs.begin(); j != noteOffs.end(); j++) - { - size_t note_i = (j->channel * 255) + (j->data[0] & 0x7F); - noteStates[note_i] = false; - } - - for(std::set::iterator j = markAsOn.begin(); j != markAsOn.end(); j++) - noteStates[*j] = true; - - } - /***********************************************************************************/ - - events.clear(); - events.insert(events.end(), noteOffs.begin(), noteOffs.end()); - events.insert(events.end(), metas.begin(), metas.end()); - events.insert(events.end(), controllers.begin(), controllers.end()); - events.insert(events.end(), anyOther.begin(), anyOther.end()); -} -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER -bool OPNMIDIplay::buildTrackData() -{ - fullSongTimeLength = 0.0; - loopStartTime = -1.0; - loopEndTime = -1.0; - musTitle.clear(); - musCopyright.clear(); - musTrackTitles.clear(); - musMarkers.clear(); - caugh_missing_instruments.clear(); - caugh_missing_banks_melodic.clear(); - caugh_missing_banks_percussion.clear(); - trackDataNew.clear(); - const size_t trackCount = TrackData.size(); - trackDataNew.resize(trackCount, MidiTrackQueue()); - - invalidLoop = false; - bool gotLoopStart = false, gotLoopEnd = false, gotLoopEventInThisRow = false; - //! Tick position of loop start tag - uint64_t loopStartTicks = 0; - //! Tick position of loop end tag - uint64_t loopEndTicks = 0; - //! Full length of song in ticks - uint64_t ticksSongLength = 0; - //! Cache for error message strign - char error[150]; - - CurrentPositionNew.track.clear(); - CurrentPositionNew.track.resize(trackCount); - - //! Caches note on/off states. - bool noteStates[16 * 255]; - /* This is required to carefully detect zero-length notes * - * and avoid a move of "note-off" event over "note-on" while sort. * - * Otherwise, after sort those notes will play infinite sound */ - - //Tempo change events - std::vector tempos; - - /* - * TODO: Make this be safer for memory in case of broken input data - * which may cause going away of available track data (and then give a crash!) - * - * POST: Check this more carefully for possible vulnuabilities are can crash this - */ - for(size_t tk = 0; tk < trackCount; ++tk) - { - uint64_t abs_position = 0; - int status = 0; - MidiEvent event; - bool ok = false; - uint8_t *end = TrackData[tk].data() + TrackData[tk].size(); - uint8_t *trackPtr = TrackData[tk].data(); - std::memset(noteStates, 0, sizeof(noteStates)); - - //Time delay that follows the first event in the track - { - MidiTrackRow evtPos; - if(opn.m_musicMode == OPN2::MODE_RSXX) - ok = true; - else - evtPos.delay = ReadVarLenEx(&trackPtr, end, ok); - if(!ok) - { - int len = snprintf(error, 150, "buildTrackData: Can't read variable-length value at begin of track %d.\n", (int)tk); - if((len > 0) && (len < 150)) - errorString += std::string(error, (size_t)len); - return false; - } - - //HACK: Begin every track with "Reset all controllers" event to avoid controllers state break came from end of song - for(uint8_t chan = 0; chan < 16; chan++) - { - MidiEvent event; - event.type = MidiEvent::T_CTRLCHANGE; - event.channel = chan; - event.data.push_back(121); - event.data.push_back(0); - evtPos.events.push_back(event); - } - - evtPos.absPos = abs_position; - abs_position += evtPos.delay; - trackDataNew[tk].push_back(evtPos); - } - - MidiTrackRow evtPos; - do - { - event = parseEvent(&trackPtr, end, status); - if(!event.isValid) - { - int len = snprintf(error, 150, "buildTrackData: Fail to parse event in the track %d.\n", (int)tk); - if((len > 0) && (len < 150)) - errorString += std::string(error, (size_t)len); - return false; - } - - evtPos.events.push_back(event); - if(event.type == MidiEvent::T_SPECIAL) - { - if(event.subtype == MidiEvent::ST_TEMPOCHANGE) - { - event.absPosition = abs_position; - tempos.push_back(event); - } - else if(!invalidLoop && (event.subtype == MidiEvent::ST_LOOPSTART)) - { - /* - * loopStart is invalid when: - * - starts together with loopEnd - * - appears more than one time in same MIDI file - */ - if(gotLoopStart || gotLoopEventInThisRow) - invalidLoop = true; - else - { - gotLoopStart = true; - loopStartTicks = abs_position; - } - //In this row we got loop event, register this! - gotLoopEventInThisRow = true; - } - else if(!invalidLoop && (event.subtype == MidiEvent::ST_LOOPEND)) - { - /* - * loopEnd is invalid when: - * - starts before loopStart - * - starts together with loopStart - * - appars more than one time in same MIDI file - */ - if(gotLoopEnd || gotLoopEventInThisRow) - invalidLoop = true; - else - { - gotLoopEnd = true; - loopEndTicks = abs_position; - } - //In this row we got loop event, register this! - gotLoopEventInThisRow = true; - } - } - - if(event.subtype != MidiEvent::ST_ENDTRACK)//Don't try to read delta after EndOfTrack event! - { - evtPos.delay = ReadVarLenEx(&trackPtr, end, ok); - if(!ok) - { - /* End of track has been reached! However, there is no EOT event presented */ - event.type = MidiEvent::T_SPECIAL; - event.subtype = MidiEvent::ST_ENDTRACK; - } - } - - if((evtPos.delay > 0) || (event.subtype == MidiEvent::ST_ENDTRACK)) - { - evtPos.absPos = abs_position; - abs_position += evtPos.delay; - evtPos.sortEvents(noteStates); - trackDataNew[tk].push_back(evtPos); - evtPos.reset(); - gotLoopEventInThisRow = false; - } - } - while((trackPtr <= end) && (event.subtype != MidiEvent::ST_ENDTRACK)); - - if(ticksSongLength < abs_position) - ticksSongLength = abs_position; - //Set the chain of events begin - if(trackDataNew[tk].size() > 0) - CurrentPositionNew.track[tk].pos = trackDataNew[tk].begin(); - } - - if(gotLoopStart && !gotLoopEnd) - { - gotLoopEnd = true; - loopEndTicks = ticksSongLength; - } - - //loopStart must be located before loopEnd! - if(loopStartTicks >= loopEndTicks) - invalidLoop = true; - - /********************************************************************************/ - //Calculate time basing on collected tempo events - /********************************************************************************/ - for(size_t tk = 0; tk < trackCount; ++tk) - { - fraction currentTempo = Tempo; - double time = 0.0; - uint64_t abs_position = 0; - size_t tempo_change_index = 0; - MidiTrackQueue &track = trackDataNew[tk]; - if(track.empty()) - continue;//Empty track is useless! - - #ifdef DEBUG_TIME_CALCULATION - std::fprintf(stdout, "\n============Track %" PRIuPTR "=============\n", tk); - std::fflush(stdout); - #endif - - MidiTrackRow *posPrev = &(*(track.begin()));//First element - for(MidiTrackQueue::iterator it = track.begin(); it != track.end(); it++) - { - #ifdef DEBUG_TIME_CALCULATION - bool tempoChanged = false; - #endif - MidiTrackRow &pos = *it; - if((posPrev != &pos) && //Skip first event - (!tempos.empty()) && //Only when in-track tempo events are available - (tempo_change_index < tempos.size()) - ) - { - // If tempo event is going between of current and previous event - if(tempos[tempo_change_index].absPosition <= pos.absPos) - { - //Stop points: begin point and tempo change points are before end point - std::vector points; - fraction t; - TempoChangePoint firstPoint = {posPrev->absPos, currentTempo}; - points.push_back(firstPoint); - - //Collect tempo change points between previous and current events - do - { - TempoChangePoint tempoMarker; - MidiEvent &tempoPoint = tempos[tempo_change_index]; - tempoMarker.absPos = tempoPoint.absPosition; - tempoMarker.tempo = InvDeltaTicks * fraction(ReadBEint(tempoPoint.data.data(), tempoPoint.data.size())); - points.push_back(tempoMarker); - tempo_change_index++; - } - while((tempo_change_index < tempos.size()) && - (tempos[tempo_change_index].absPosition <= pos.absPos)); - - // Re-calculate time delay of previous event - time -= posPrev->timeDelay; - posPrev->timeDelay = 0.0; - - for(size_t i = 0, j = 1; j < points.size(); i++, j++) - { - /* If one or more tempo events are appears between of two events, - * calculate delays between each tempo point, begin and end */ - uint64_t midDelay = 0; - //Delay between points - midDelay = points[j].absPos - points[i].absPos; - //Time delay between points - t = midDelay * currentTempo; - posPrev->timeDelay += t.value(); - - //Apply next tempo - currentTempo = points[j].tempo; - #ifdef DEBUG_TIME_CALCULATION - tempoChanged = true; - #endif - } - //Then calculate time between last tempo change point and end point - TempoChangePoint tailTempo = points.back(); - uint64_t postDelay = pos.absPos - tailTempo.absPos; - t = postDelay * currentTempo; - posPrev->timeDelay += t.value(); - - //Store Common time delay - posPrev->time = time; - time += posPrev->timeDelay; - } - } - - fraction t = pos.delay * currentTempo; - pos.timeDelay = t.value(); - pos.time = time; - time += pos.timeDelay; - - //Capture markers after time value calculation - for(size_t i = 0; i < pos.events.size(); i++) - { - MidiEvent &e = pos.events[i]; - if((e.type == MidiEvent::T_SPECIAL) && (e.subtype == MidiEvent::ST_MARKER)) - { - MIDI_MarkerEntry marker; - marker.label = std::string((char *)e.data.data(), e.data.size()); - marker.pos_ticks = pos.absPos; - marker.pos_time = pos.time; - musMarkers.push_back(marker); - } - } - - //Capture loop points time positions - if(!invalidLoop) - { - // Set loop points times - if(loopStartTicks == pos.absPos) - loopStartTime = pos.time; - else if(loopEndTicks == pos.absPos) - loopEndTime = pos.time; - } - - #ifdef DEBUG_TIME_CALCULATION - std::fprintf(stdout, "= %10" PRId64 " = %10f%s\n", pos.absPos, pos.time, tempoChanged ? " <----TEMPO CHANGED" : ""); - std::fflush(stdout); - #endif - - abs_position += pos.delay; - posPrev = &pos; - } - - if(time > fullSongTimeLength) - fullSongTimeLength = time; - } - - fullSongTimeLength += postSongWaitDelay; - //Set begin of the music - trackBeginPositionNew = CurrentPositionNew; - //Initial loop position will begin at begin of track until passing of the loop point - LoopBeginPositionNew = CurrentPositionNew; - - /********************************************************************************/ - //Resolve "hell of all times" of too short drum notes: - //move too short percussion note-offs far far away as possible - /********************************************************************************/ - #if 1 //Use this to record WAVEs for comparison before/after implementing of this - if(opn.m_musicMode == OPN2::MODE_MIDI)//Percussion fix is needed for MIDI only, not for IMF/RSXX or CMF - { - //! Minimal real time in seconds -#define DRUM_NOTE_MIN_TIME 0.03 - //! Minimal ticks count -#define DRUM_NOTE_MIN_TICKS 15 - struct NoteState - { - double delay; - uint64_t delayTicks; - bool isOn; - char ___pad[7]; - } drNotes[255]; - uint16_t banks[16]; - - for(size_t tk = 0; tk < trackCount; ++tk) - { - std::memset(drNotes, 0, sizeof(drNotes)); - std::memset(banks, 0, sizeof(banks)); - MidiTrackQueue &track = trackDataNew[tk]; - if(track.empty()) - continue;//Empty track is useless! - - for(MidiTrackQueue::iterator it = track.begin(); it != track.end(); it++) - { - MidiTrackRow &pos = *it; - - for(ssize_t e = 0; e < (ssize_t)pos.events.size(); e++) - { - MidiEvent *et = &pos.events[(size_t)e]; - - /* Set MSB/LSB bank */ - if(et->type == MidiEvent::T_CTRLCHANGE) - { - uint8_t ctrlno = et->data[0]; - uint8_t value = et->data[1]; - switch(ctrlno) - { - case 0: // Set bank msb (GM bank) - banks[et->channel] = uint16_t(uint16_t(value) << 8) | uint16_t(banks[et->channel] & 0x00FF); - break; - case 32: // Set bank lsb (XG bank) - banks[et->channel] = (banks[et->channel] & 0xFF00) | (uint16_t(value) & 0x00FF); - break; - } - continue; - } - - bool percussion = (et->channel == 9) || - banks[et->channel] == 0x7E00 || //XG SFX1/SFX2 channel (16128 signed decimal) - banks[et->channel] == 0x7F00; //XG Percussion channel (16256 signed decimal) - if(!percussion) - continue; - - if(et->type == MidiEvent::T_NOTEON) - { - uint8_t note = et->data[0] & 0x7F; - NoteState &ns = drNotes[note]; - ns.isOn = true; - ns.delay = 0.0; - ns.delayTicks = 0; - } - else if(et->type == MidiEvent::T_NOTEOFF) - { - uint8_t note = et->data[0] & 0x7F; - NoteState &ns = drNotes[note]; - if(ns.isOn) - { - ns.isOn = false; - if(ns.delayTicks < DRUM_NOTE_MIN_TICKS || ns.delay < DRUM_NOTE_MIN_TIME)//If note is too short - { - //Move it into next event position if that possible - for(MidiTrackQueue::iterator itNext = it; - itNext != track.end(); - itNext++) - { - MidiTrackRow &posN = *itNext; - if(ns.delayTicks > DRUM_NOTE_MIN_TICKS && ns.delay > DRUM_NOTE_MIN_TIME) - { - //Put note-off into begin of next event list - posN.events.insert(posN.events.begin(), pos.events[(size_t)e]); - //Renive this event from a current row - pos.events.erase(pos.events.begin() + (int)e); - e--; - break; - } - ns.delay += posN.timeDelay; - ns.delayTicks += posN.delay; - } - } - ns.delay = 0.0; - ns.delayTicks = 0; - } - } - } - - //Append time delays to sustaining notes - for(size_t no = 0; no < 128; no++) - { - NoteState &ns = drNotes[no]; - if(ns.isOn) - { - ns.delay += pos.timeDelay; - ns.delayTicks += pos.delay; - } - } - } - } -#undef DRUM_NOTE_MIN_TIME -#undef DRUM_NOTE_MIN_TICKS - } - #endif - - return true; -} -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER - - OPNMIDIplay::OPNMIDIplay(unsigned long sampleRate) : + m_masterVolume(MasterVolumeDefault), + m_sysExDeviceId(0), + m_synthMode(Mode_XG), m_arpeggioCounter(0) -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - , fullSongTimeLength(0.0), - postSongWaitDelay(1.0), - loopStartTime(-1.0), - loopEndTime(-1.0), - tempoMultiplier(1.0), - atEnd(false), - loopStart(false), - loopEnd(false), - invalidLoop(false) +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) + , m_audioTickCounter(0) #endif { - devices.clear(); + m_midiDevices.clear(); - m_setup.emulator = OPNMIDI_EMU_MAME; + m_setup.emulator = opn2_getLowestEmulator(); m_setup.runAtPcmRate = false; m_setup.PCM_RATE = sampleRate; @@ -680,245 +100,117 @@ OPNMIDIplay::OPNMIDIplay(unsigned long sampleRate) : m_setup.maxdelay = 512.0 / (double)m_setup.PCM_RATE; m_setup.OpnBank = 0; - m_setup.NumCards = 2; + m_setup.numChips = 2; m_setup.LogarithmicVolumes = false; m_setup.VolumeModel = OPNMIDI_VolumeModel_AUTO; + m_setup.lfoEnable = -1; + m_setup.lfoFrequency = -1; //m_setup.SkipForward = 0; - m_setup.loopingIsEnabled = false; m_setup.ScaleModulators = 0; m_setup.fullRangeBrightnessCC74 = false; m_setup.delay = 0.0; m_setup.carry = 0.0; m_setup.tick_skip_samples_delay = 0; +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER + initSequencerInterface(); +#endif + resetMIDI(); applySetup(); - ChooseDevice("none"); realTime_ResetState(); } void OPNMIDIplay::applySetup() { + m_synth.m_musicMode = OPN2::MODE_MIDI; + m_setup.tick_skip_samples_delay = 0; - opn.ScaleModulators = (m_setup.ScaleModulators != 0); - opn.runAtPcmRate = m_setup.runAtPcmRate; - opn.m_musicMode = OPN2::MODE_MIDI; + m_synth.m_runAtPcmRate = m_setup.runAtPcmRate; + + m_synth.m_scaleModulators = (m_setup.ScaleModulators != 0); + if(m_setup.LogarithmicVolumes != 0) - opn.ChangeVolumeRangesModel(OPNMIDI_VolumeModel_CMF); + m_synth.setVolumeScaleModel(OPNMIDI_VolumeModel_NativeOPN2); else - opn.ChangeVolumeRangesModel(static_cast(m_setup.VolumeModel)); + m_synth.setVolumeScaleModel(static_cast(m_setup.VolumeModel)); + if(m_setup.VolumeModel == OPNMIDI_VolumeModel_AUTO) - opn.m_volumeScale = OPN2::VOLUME_Generic; + m_synth.m_volumeScale = (OPN2::VolumesScale)m_synth.m_insBankSetup.volumeModel; - opn.NumCards = m_setup.NumCards; + m_synth.m_numChips = m_setup.numChips; - opn.Reset(m_setup.emulator, m_setup.PCM_RATE); - ch.clear(); - ch.resize(opn.NumChannels, OpnChannel()); + if(m_setup.lfoEnable < 0) + m_synth.m_lfoEnable = (m_synth.m_insBankSetup.lfoEnable != 0); + else + m_synth.m_lfoEnable = (m_setup.lfoEnable != 0); + + if(m_setup.lfoFrequency < 0) + m_synth.m_lfoFrequency = m_synth.m_insBankSetup.lfoFrequency; + else + m_synth.m_lfoFrequency = m_setup.lfoFrequency; + + m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); + m_chipChannels.clear(); + m_chipChannels.resize(m_synth.m_numChannels, OpnChannel()); // Reset the arpeggio counter m_arpeggioCounter = 0; } -uint64_t OPNMIDIplay::ReadVarLen(uint8_t **ptr) +void OPNMIDIplay::partialReset() { - uint64_t result = 0; - for(;;) - { - uint8_t byte = *((*ptr)++); - result = (result << 7) + (byte & 0x7F); - if(!(byte & 0x80)) - break; - } - return result; + realTime_panic(); + m_setup.tick_skip_samples_delay = 0; + m_synth.m_runAtPcmRate = m_setup.runAtPcmRate; + m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); + m_chipChannels.clear(); + m_chipChannels.resize(m_synth.m_numChannels); } -uint64_t OPNMIDIplay::ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok) +void OPNMIDIplay::resetMIDI() { - uint64_t result = 0; - ok = false; + m_masterVolume = MasterVolumeDefault; + m_sysExDeviceId = 0; + m_synthMode = Mode_XG; + m_arpeggioCounter = 0; - for(;;) - { - if(*ptr >= end) - return 2; - unsigned char byte = *((*ptr)++); - result = (result << 7) + (byte & 0x7F); - if(!(byte & 0x80)) - break; - } + m_midiChannels.clear(); + m_midiChannels.resize(16, MIDIchannel()); - ok = true; - return result; + caugh_missing_instruments.clear(); + caugh_missing_banks_melodic.clear(); + caugh_missing_banks_percussion.clear(); } -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER -double OPNMIDIplay::Tick(double s, double granularity) +void OPNMIDIplay::TickIterators(double s) { - s *= tempoMultiplier; - #ifdef ENABLE_BEGIN_SILENCE_SKIPPING - if(CurrentPositionNew.began) - #endif - CurrentPositionNew.wait -= s; - CurrentPositionNew.absTimePosition += s; - - int antiFreezeCounter = 10000;//Limit 10000 loops to avoid freezing - while((CurrentPositionNew.wait <= granularity * 0.5) && (antiFreezeCounter > 0)) - { - //std::fprintf(stderr, "wait = %g...\n", CurrentPosition.wait); - if(!ProcessEventsNew()) - break; - if(CurrentPositionNew.wait <= 0.0) - antiFreezeCounter--; - } - - if(antiFreezeCounter <= 0) - CurrentPositionNew.wait += 1.0;/* Add extra 1 second when over 10000 events - with zero delay are been detected */ - - for(uint16_t c = 0; c < opn.NumChannels; ++c) - ch[c].AddAge(static_cast(s * 1000.0)); - - UpdateVibrato(s); - UpdateArpeggio(s); - - if(CurrentPositionNew.wait < 0.0)//Avoid negative delay value! - return 0.0; - - return CurrentPositionNew.wait; + for(uint16_t c = 0; c < m_synth.m_numChannels; ++c) + m_chipChannels[c].addAge(static_cast(s * 1e6)); + updateVibrato(s); + updateArpeggio(s); +#if !defined(ADLMIDI_AUDIO_TICK_HANDLER) + updateGlide(s); +#endif } -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER - -void OPNMIDIplay::TickIteratos(double s) -{ - for(uint16_t c = 0; c < opn.NumChannels; ++c) - ch[c].AddAge(static_cast(s * 1000.0)); - UpdateVibrato(s); - UpdateArpeggio(s); -} - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER -void OPNMIDIplay::seek(double seconds) -{ - if(seconds < 0.0) - return;//Seeking negative position is forbidden! :-P - const double granularity = m_setup.mindelay, - granualityHalf = granularity * 0.5, - s = seconds;//m_setup.delay < m_setup.maxdelay ? m_setup.delay : m_setup.maxdelay; - - /* Attempt to go away out of song end must rewind position to begin */ - if(seconds > fullSongTimeLength) - { - rewind(); - return; - } - - bool loopFlagState = m_setup.loopingIsEnabled; - // Turn loop pooints off because it causes wrong position rememberin on a quick seek - m_setup.loopingIsEnabled = false; - - /* - * Seeking search is similar to regular ticking, except of next things: - * - We don't processsing arpeggio and vibrato - * - To keep correctness of the state after seek, begin every search from begin - * - All sustaining notes must be killed - * - Ignore Note-On events - */ - rewind(); - - /* - * Set "loop Start" to false to prevent overwrite of loopStart position with - * seek destinition position - * - * TODO: Detect & set loopStart position on load time to don't break loop while seeking - */ - loopStart = false; - - while((CurrentPositionNew.absTimePosition < seconds) && - (CurrentPositionNew.absTimePosition < fullSongTimeLength)) - { - CurrentPositionNew.wait -= s; - CurrentPositionNew.absTimePosition += s; - int antiFreezeCounter = 10000;//Limit 10000 loops to avoid freezing - double dstWait = CurrentPositionNew.wait + granualityHalf; - while((CurrentPositionNew.wait <= granualityHalf)/*&& (antiFreezeCounter > 0)*/) - { - //std::fprintf(stderr, "wait = %g...\n", CurrentPosition.wait); - if(!ProcessEventsNew(true)) - break; - //Avoid freeze because of no waiting increasing in more than 10000 cycles - if(CurrentPositionNew.wait <= dstWait) - antiFreezeCounter--; - else - { - dstWait = CurrentPositionNew.wait + granualityHalf; - antiFreezeCounter = 10000; - } - } - if(antiFreezeCounter <= 0) - CurrentPositionNew.wait += 1.0;/* Add extra 1 second when over 10000 events - with zero delay are been detected */ - } - - if(CurrentPositionNew.wait < 0.0) - CurrentPositionNew.wait = 0.0; - - m_setup.loopingIsEnabled = loopFlagState; - m_setup.delay = CurrentPositionNew.wait; - m_setup.carry = 0.0; -} - -double OPNMIDIplay::tell() -{ - return CurrentPositionNew.absTimePosition; -} - -double OPNMIDIplay::timeLength() -{ - return fullSongTimeLength; -} - -double OPNMIDIplay::getLoopStart() -{ - return loopStartTime; -} - -double OPNMIDIplay::getLoopEnd() -{ - return loopEndTime; -} - -void OPNMIDIplay::rewind() -{ - Panic(); - KillSustainingNotes(-1, -1); - CurrentPositionNew = trackBeginPositionNew; - atEnd = false; - loopStart = true; - loopEnd = false; - //invalidLoop = false;//No more needed here as this flag is set on load time -} - -void OPNMIDIplay::setTempo(double tempo) -{ - tempoMultiplier = tempo; -} -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER void OPNMIDIplay::realTime_ResetState() { - for(size_t ch = 0; ch < Ch.size(); ch++) + for(size_t ch = 0; ch < m_midiChannels.size(); ch++) { - MIDIchannel &chan = Ch[ch]; + MIDIchannel &chan = m_midiChannels[ch]; chan.resetAllControllers(); - chan.volume = (opn.m_musicMode == OPN2::MODE_RSXX) ? 127 : 100; + chan.volume = (m_synth.m_musicMode == OPN2::MODE_RSXX) ? 127 : 100; chan.vibpos = 0.0; chan.lastlrpn = 0; chan.lastmrpn = 0; chan.nrpn = false; - NoteUpdate_All(uint16_t(ch), Upd_All); - NoteUpdate_All(uint16_t(ch), Upd_Off); + if((m_synthMode & Mode_GS) != 0)// Reset custom drum channels on GS + chan.is_xg_percussion = false; + noteUpdateAll(uint16_t(ch), Upd_All); + noteUpdateAll(uint16_t(ch), Upd_Off); } + m_masterVolume = MasterVolumeDefault; } bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) @@ -926,20 +218,23 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit if(note >= 127) note = 127; - if((opn.m_musicMode == OPN2::MODE_RSXX) && (velocity != 0)) + if((m_synth.m_musicMode == OPN2::MODE_RSXX) && (velocity != 0)) { // Check if this is just a note after-touch - MIDIchannel::activenoteiterator i = Ch[channel].activenotes_find(note); + MIDIchannel::activenoteiterator i = m_midiChannels[channel].activenotes_find(note); if(i) { + const int veloffset = i->ains->midi_velocity_offset; + velocity = (uint8_t)std::min(127, std::max(1, (int)velocity + veloffset)); i->vol = velocity; - NoteUpdate(channel, i, Upd_Volume); + noteUpdate(channel, i, Upd_Volume); return false; } } - channel = channel % 16; - NoteOff(channel, note); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + noteOff(channel, note); // On Note on, Keyoff the note first, just in case keyoff // was omitted; this fixes Dance of sugar-plum fairy // by Microsoft. Now that we've done a Keyoff, @@ -948,54 +243,62 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit if(velocity == 0) return false; - MIDIchannel &midiChan = Ch[channel]; + MIDIchannel &midiChan = m_midiChannels[channel]; size_t midiins = midiChan.patch; - bool isPercussion = (channel % 16 == 9); - bool isXgPercussion = false; + bool isPercussion = (channel % 16 == 9) || midiChan.is_xg_percussion; - uint16_t bank = 0; + size_t bank = 0; if(midiChan.bank_msb || midiChan.bank_lsb) { - bank = (uint16_t(midiChan.bank_msb) * 256) + uint16_t(midiChan.bank_lsb); - //0x7E00 - XG SFX1/SFX2 channel (16128 signed decimal) - //0x7F00 - XG Percussion channel (16256 signed decimal) - if(bank == 0x7E00 || bank == 0x7F00) - { - //Let XG SFX1/SFX2 bank will have LSB==1 (128...255 range in WOPN file) - //Let XG Percussion bank will use (0...127 range in WOPN file) - bank = (uint16_t)midiins + ((bank == 0x7E00) ? 128 : 0); // MIDI instrument defines the patch - midiins = note; // Percussion instrument - isXgPercussion = true; - isPercussion = false; - } + if((m_synthMode & Mode_GS) != 0) //in GS mode ignore LSB + bank = (midiChan.bank_msb * 256); + else + bank = (midiChan.bank_msb * 256) + midiChan.bank_lsb; } if(isPercussion) { - bank = (uint16_t)midiins; // MIDI instrument defines the patch + // == XG bank numbers == + // 0x7E00 - XG "SFX Kits" SFX1/SFX2 channel (16128 signed decimal) + // 0x7F00 - XG "Drum Kits" Percussion channel (16256 signed decimal) + + // MIDI instrument defines the patch: + if((m_synthMode & Mode_XG) != 0) + { + // Let XG SFX1/SFX2 bank will go in 128...255 range of LSB in WOPN file) + // Let XG Percussion bank will use (0...127 LSB range in WOPN file) + + // Choose: SFX or Drum Kits + bank = midiins + ((bank == 0x7E00) ? 128 : 0); + } + else + { + bank = midiins; + } midiins = note; // Percussion instrument } - if(isPercussion || isXgPercussion) + + if(isPercussion) bank += OPN2::PercussionTag; - const opnInstMeta2 *ains = &OPN2::emptyInstrument; + const opnInstMeta2 *ains = &OPN2::m_emptyInstrument; //Set bank bank const OPN2::Bank *bnk = NULL; if((bank & ~(uint16_t)OPN2::PercussionTag) > 0) { - OPN2::BankMap::iterator b = opn.dynamic_banks.find(bank); - if(b != opn.dynamic_banks.end()) + OPN2::BankMap::iterator b = m_synth.m_insBanks.find(bank); + if(b != m_synth.m_insBanks.end()) bnk = &b->second; if(bnk) ains = &bnk->ins[midiins]; else if(hooks.onDebugMessage) { - std::set &missing = (isPercussion || isXgPercussion) ? + std::set &missing = (isPercussion) ? caugh_missing_banks_percussion : caugh_missing_banks_melodic; - const char *text = (isPercussion || isXgPercussion) ? + const char *text = (isPercussion) ? "percussion" : "melodic"; if(missing.insert(bank).second) hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing %s MIDI bank %i (patch %i)", channel, text, bank, midiins); @@ -1004,25 +307,19 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit //Or fall back to first bank if(ains->flags & opnInstMeta::Flag_NoSound) { - OPN2::BankMap::iterator b = opn.dynamic_banks.find(bank & OPN2::PercussionTag); - if(b != opn.dynamic_banks.end()) + OPN2::BankMap::iterator b = m_synth.m_insBanks.find(bank & OPN2::PercussionTag); + if(b != m_synth.m_insBanks.end()) bnk = &b->second; if(bnk) ains = &bnk->ins[midiins]; } - /* - if(MidCh%16 == 9 || (midiins != 32 && midiins != 46 && midiins != 48 && midiins != 50)) - break; // HACK - if(midiins == 46) vol = (vol*7)/10; // HACK - if(midiins == 48 || midiins == 50) vol /= 4; // HACK - */ - //if(midiins == 56) vol = vol*6/10; // HACK + const int veloffset = ains->midi_velocity_offset; + velocity = (uint8_t)std::min(127, std::max(1, (int)velocity + veloffset)); - int16_t tone = note; - - if(!isPercussion && !isXgPercussion && (bank > 0)) // For non-zero banks + int32_t tone = note; + if(!isPercussion && (bank > 0)) // For non-zero banks { if(ains->flags & opnInstMeta::Flag_NoSound) { @@ -1030,7 +327,7 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit { if(!caugh_missing_instruments.count(static_cast(midiins))) { - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Caugh a blank instrument %i (offset %i) in the MIDI bank %u", channel, midiChan.patch, midiins, bank); + hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Caught a blank instrument %i (offset %i) in the MIDI bank %u", channel, midiChan.patch, midiins, bank); caugh_missing_instruments.insert(static_cast(midiins)); } } @@ -1057,15 +354,30 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit //bool pseudo_4op = ains.flags & opnInstMeta::Flag_Pseudo8op; //if((opn.AdlPercussionMode == 1) && PercussionMap[midiins & 0xFF]) i[1] = i[0]; + bool isBlankNote = (ains->flags & opnInstMeta::Flag_NoSound) != 0; + if(hooks.onDebugMessage) { - if(!caugh_missing_instruments.count(static_cast(midiins)) && (ains->flags & opnInstMeta::Flag_NoSound)) + if(!caugh_missing_instruments.count(static_cast(midiins)) && isBlankNote) { hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing instrument %i", channel, midiins); caugh_missing_instruments.insert(static_cast(midiins)); } } + if(isBlankNote) + { + // Don't even try to play the blank instrument! But, insert the dummy note. + std::pair + dummy = midiChan.activenotes_insert(note); + dummy.first->isBlank = true; + dummy.first->ains = NULL; + dummy.first->chip_channels_count = 0; + // Record the last note on MIDI channel as source of portamento + midiChan.portamentoSource = static_cast(note); + return false; + } + // Allocate AdLib channel (the physical sound channel for the note) int32_t adlchannel[MIDIchannel::NoteInfo::MaxNumPhysChans] = { -1, -1 }; @@ -1082,7 +394,7 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit int32_t c = -1; int32_t bs = -0x7FFFFFFFl; - for(size_t a = 0; a < (size_t)opn.NumChannels; ++a) + for(size_t a = 0; a < (size_t)m_synth.m_numChannels; ++a) { if(ccount == 1 && static_cast(a) == adlchannel[0]) continue; // ^ Don't use the same channel for primary&secondary @@ -1101,7 +413,7 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit // if(opn.four_op_category[a] != expected_mode) // continue; //} - int64_t s = CalculateAdlChannelGoodness(a, voices[ccount], channel); + int64_t s = calculateChipChannelGoodness(a, voices[ccount]); if(s > bs) { bs = (int32_t)s; // Best candidate wins @@ -1118,7 +430,7 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit continue; // Could not play this note. Ignore it. } - PrepareAdlChannelForNewNote(static_cast(c), voices[ccount]); + prepareChipChannelForNewNote(static_cast(c), voices[ccount]); adlchannel[ccount] = c; } @@ -1131,16 +443,39 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit //if(hooks.onDebugMessage) // hooks.onDebugMessage(hooks.onDebugMessage_userData, "i1=%d:%d, i2=%d:%d", i[0],adlchannel[0], i[1],adlchannel[1]); + if(midiChan.softPedal) // Apply Soft Pedal level reducing + velocity = static_cast(std::floor(static_cast(velocity) * 0.8f)); + // Allocate active note for MIDI channel std::pair ir = midiChan.activenotes_insert(note); ir.first->vol = velocity; ir.first->vibrato = midiChan.noteAftertouch[note]; - ir.first->tone = tone; + ir.first->noteTone = static_cast(tone); + ir.first->currentTone = tone; + ir.first->glideRate = HUGE_VAL; ir.first->midiins = midiins; + ir.first->isPercussion = isPercussion; + ir.first->isBlank = isBlankNote; ir.first->ains = ains; ir.first->chip_channels_count = 0; + int8_t currentPortamentoSource = midiChan.portamentoSource; + double currentPortamentoRate = midiChan.portamentoRate; + bool portamentoEnable = + midiChan.portamentoEnable && currentPortamentoRate != HUGE_VAL && !isPercussion; + // Record the last note on MIDI channel as source of portamento + midiChan.portamentoSource = static_cast(note); + // midiChan.portamentoSource = portamentoEnable ? (int8_t)note : (int8_t)-1; + + // Enable gliding on portamento note + if (portamentoEnable && currentPortamentoSource >= 0) + { + ir.first->currentTone = currentPortamentoSource; + ir.first->glideRate = currentPortamentoRate; + ++midiChan.gliding_note_count; + } + for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) { int32_t c = adlchannel[ccount]; @@ -1149,21 +484,34 @@ bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocit uint16_t chipChan = static_cast(adlchannel[ccount]); ir.first->phys_ensure_find_or_create(chipChan)->assign(voices[ccount]); } - NoteUpdate(channel, ir.first, Upd_All | Upd_Patch); + + noteUpdate(channel, ir.first, Upd_All | Upd_Patch); + + for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) + { + int32_t c = adlchannel[ccount]; + if(c < 0) + continue; + m_chipChannels[c].recent_ins = voices[ccount]; + m_chipChannels[c].addAge(0); + } + return true; } void OPNMIDIplay::realTime_NoteOff(uint8_t channel, uint8_t note) { - channel = channel % 16; - NoteOff(channel, note); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + noteOff(channel, note); } void OPNMIDIplay::realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal) { - channel = channel % 16; - MIDIchannel &chan = Ch[channel]; - MIDIchannel::activenoteiterator i = Ch[channel].activenotes_find(note); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + MIDIchannel &chan = m_midiChannels[channel]; + MIDIchannel::activenoteiterator i = m_midiChannels[channel].activenotes_find(note); if(i) { i->vibrato = atVal; @@ -1182,86 +530,99 @@ void OPNMIDIplay::realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t void OPNMIDIplay::realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal) { - channel = channel % 16; - Ch[channel].aftertouch = atVal; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].aftertouch = atVal; } void OPNMIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t value) { - channel = channel % 16; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; switch(type) { case 1: // Adjust vibrato //UI.PrintLn("%u:vibrato %d", MidCh,value); - Ch[channel].vibrato = value; + m_midiChannels[channel].vibrato = value; break; case 0: // Set bank msb (GM bank) - Ch[channel].bank_msb = value; - Ch[channel].is_xg_percussion = isXgPercChannel(Ch[channel].bank_msb, Ch[channel].bank_lsb); + m_midiChannels[channel].bank_msb = value; + if((m_synthMode & Mode_GS) == 0)// Don't use XG drums on GS synth mode + m_midiChannels[channel].is_xg_percussion = isXgPercChannel(m_midiChannels[channel].bank_msb, m_midiChannels[channel].bank_lsb); break; case 32: // Set bank lsb (XG bank) - Ch[channel].bank_lsb = value; - Ch[channel].is_xg_percussion = isXgPercChannel(Ch[channel].bank_msb, Ch[channel].bank_lsb); + m_midiChannels[channel].bank_lsb = value; + if((m_synthMode & Mode_GS) == 0)// Don't use XG drums on GS synth mode + m_midiChannels[channel].is_xg_percussion = isXgPercChannel(m_midiChannels[channel].bank_msb, m_midiChannels[channel].bank_lsb); break; case 5: // Set portamento msb - Ch[channel].portamento = static_cast((Ch[channel].portamento & 0x7F) | (value << 7)); - //UpdatePortamento(MidCh); + m_midiChannels[channel].portamento = static_cast((m_midiChannels[channel].portamento & 0x007F) | (value << 7)); + updatePortamento(channel); break; case 37: // Set portamento lsb - Ch[channel].portamento = (Ch[channel].portamento & 0x3F80) | (value); - //UpdatePortamento(MidCh); + m_midiChannels[channel].portamento = static_cast((m_midiChannels[channel].portamento & 0x3F80) | (value)); + updatePortamento(channel); break; case 65: // Enable/disable portamento - // value >= 64 ? enabled : disabled - //UpdatePortamento(MidCh); + m_midiChannels[channel].portamentoEnable = value >= 64; + updatePortamento(channel); break; case 7: // Change volume - Ch[channel].volume = value; - NoteUpdate_All(channel, Upd_Volume); + m_midiChannels[channel].volume = value; + noteUpdateAll(channel, Upd_Volume); break; case 74: // Change brightness - Ch[channel].brightness = value; - NoteUpdate_All(channel, Upd_Volume); + m_midiChannels[channel].brightness = value; + noteUpdateAll(channel, Upd_Volume); break; case 64: // Enable/disable sustain - Ch[channel].sustain = value; - if(!value) KillSustainingNotes(channel); + m_midiChannels[channel].sustain = (value >= 64); + if(!m_midiChannels[channel].sustain) + killSustainingNotes(channel, -1, OpnChannel::LocationData::Sustain_Pedal); + break; + + case 66: // Enable/disable sostenuto + if(value >= 64) //Find notes and mark them as sostenutoed + markSostenutoNotes(channel); + else + killSustainingNotes(channel, -1, OpnChannel::LocationData::Sustain_Sostenuto); + break; + + case 67: // Enable/disable soft-pedal + m_midiChannels[channel].softPedal = (value >= 64); break; case 11: // Change expression (another volume factor) - Ch[channel].expression = value; - NoteUpdate_All(channel, Upd_Volume); + m_midiChannels[channel].expression = value; + noteUpdateAll(channel, Upd_Volume); break; case 10: // Change panning - Ch[channel].panning = 0x00; - if(value < 64 + 32) Ch[channel].panning |= OPN_PANNING_LEFT; - if(value >= 64 - 32) Ch[channel].panning |= OPN_PANNING_RIGHT; - NoteUpdate_All(channel, Upd_Pan); + m_midiChannels[channel].panning = value; + noteUpdateAll(channel, Upd_Pan); break; case 121: // Reset all controllers - Ch[channel].resetAllControllers(); - //UpdatePortamento(MidCh); - NoteUpdate_All(channel, Upd_Pan + Upd_Volume + Upd_Pitch); + m_midiChannels[channel].resetAllControllers(); + noteUpdateAll(channel, Upd_Pan + Upd_Volume + Upd_Pitch); // Kill all sustained notes - KillSustainingNotes(channel); + killSustainingNotes(channel, -1, OpnChannel::LocationData::Sustain_ANY); break; case 120: // All sounds off - NoteUpdate_All(channel, Upd_OffMute); + noteUpdateAll(channel, Upd_OffMute); break; case 123: // All notes off - NoteUpdate_All(channel, Upd_Off); + noteUpdateAll(channel, Upd_Off); break; case 91: @@ -1280,34 +641,34 @@ void OPNMIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t val break; // Phaser effect depth. We don't do. case 98: - Ch[channel].lastlrpn = value; - Ch[channel].nrpn = true; + m_midiChannels[channel].lastlrpn = value; + m_midiChannels[channel].nrpn = true; break; case 99: - Ch[channel].lastmrpn = value; - Ch[channel].nrpn = true; + m_midiChannels[channel].lastmrpn = value; + m_midiChannels[channel].nrpn = true; break; case 100: - Ch[channel].lastlrpn = value; - Ch[channel].nrpn = false; + m_midiChannels[channel].lastlrpn = value; + m_midiChannels[channel].nrpn = false; break; case 101: - Ch[channel].lastmrpn = value; - Ch[channel].nrpn = false; + m_midiChannels[channel].lastmrpn = value; + m_midiChannels[channel].nrpn = false; break; case 113: break; // Related to pitch-bender, used by missimp.mid in Duke3D case 6: - SetRPN(channel, value, true); + setRPN(channel, value, true); break; case 38: - SetRPN(channel, value, false); + setRPN(channel, value, false); break; //case 103: @@ -1322,64 +683,329 @@ void OPNMIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t val void OPNMIDIplay::realTime_PatchChange(uint8_t channel, uint8_t patch) { - channel = channel % 16; - Ch[channel].patch = patch; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].patch = patch; } void OPNMIDIplay::realTime_PitchBend(uint8_t channel, uint16_t pitch) { - channel = channel % 16; - Ch[channel].bend = int(pitch) - 8192; - NoteUpdate_All(channel, Upd_Pitch); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bend = int(pitch) - 8192; + noteUpdateAll(channel, Upd_Pitch); } void OPNMIDIplay::realTime_PitchBend(uint8_t channel, uint8_t msb, uint8_t lsb) { - channel = channel % 16; - Ch[channel].bend = int(lsb) + int(msb) * 128 - 8192; - NoteUpdate_All(channel, Upd_Pitch); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bend = int(lsb) + int(msb) * 128 - 8192; + noteUpdateAll(channel, Upd_Pitch); } void OPNMIDIplay::realTime_BankChangeLSB(uint8_t channel, uint8_t lsb) { - channel = channel % 16; - Ch[channel].bank_lsb = lsb; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bank_lsb = lsb; } void OPNMIDIplay::realTime_BankChangeMSB(uint8_t channel, uint8_t msb) { - channel = channel % 16; - Ch[channel].bank_msb = msb; + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bank_msb = msb; } void OPNMIDIplay::realTime_BankChange(uint8_t channel, uint16_t bank) { - channel = channel % 16; - Ch[channel].bank_lsb = uint8_t(bank & 0xFF); - Ch[channel].bank_msb = uint8_t((bank >> 8) & 0xFF); + if(static_cast(channel) > m_midiChannels.size()) + channel = channel % 16; + m_midiChannels[channel].bank_lsb = uint8_t(bank & 0xFF); + m_midiChannels[channel].bank_msb = uint8_t((bank >> 8) & 0xFF); +} + +void OPNMIDIplay::setDeviceId(uint8_t id) +{ + m_sysExDeviceId = id; +} + +bool OPNMIDIplay::realTime_SysEx(const uint8_t *msg, size_t size) +{ + if(size < 4 || msg[0] != 0xF0 || msg[size - 1] != 0xF7) + return false; + + unsigned manufacturer = msg[1]; + unsigned dev = msg[2]; + msg += 3; + size -= 4; + + switch(manufacturer) + { + default: + break; + case Manufacturer_UniversalNonRealtime: + case Manufacturer_UniversalRealtime: + return doUniversalSysEx( + dev, manufacturer == Manufacturer_UniversalRealtime, msg, size); + case Manufacturer_Roland: + return doRolandSysEx(dev, msg, size); + case Manufacturer_Yamaha: + return doYamahaSysEx(dev, msg, size); + } + + return false; +} + +bool OPNMIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size) +{ + bool devicematch = dev == 0x7F || dev == m_sysExDeviceId; + if(size < 2 || !devicematch) + return false; + + unsigned address = + (((unsigned)data[0] & 0x7F) << 8) | + (((unsigned)data[1] & 0x7F)); + data += 2; + size -= 2; + + switch(((unsigned)realtime << 16) | address) + { + case (0 << 16) | 0x0901: // GM System On + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System On"); + m_synthMode = Mode_GM; + realTime_ResetState(); + return true; + case (0 << 16) | 0x0902: // GM System Off + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System Off"); + m_synthMode = Mode_XG;//TODO: TEMPORARY, make something RIGHT + realTime_ResetState(); + return true; + case (1 << 16) | 0x0401: // MIDI Master Volume + if(size != 2) + break; + unsigned volume = + (((unsigned)data[0] & 0x7F)) | + (((unsigned)data[1] & 0x7F) << 7); + m_masterVolume = static_cast(volume >> 7); + for(size_t ch = 0; ch < m_midiChannels.size(); ch++) + noteUpdateAll(uint16_t(ch), Upd_Volume); + return true; + } + + return false; +} + +bool OPNMIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) +{ + bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; + if(size < 6 || !devicematch) + return false; + + unsigned model = data[0] & 0x7F; + unsigned mode = data[1] & 0x7F; + unsigned checksum = data[size - 1] & 0x7F; + data += 2; + size -= 3; + +#if !defined(OPNMIDI_SKIP_ROLAND_CHECKSUM) + { + unsigned checkvalue = 0; + for(size_t i = 0; i < size; ++i) + checkvalue += data[i] & 0x7F; + checkvalue = (128 - (checkvalue & 127)) & 127; + if(checkvalue != checksum) + { + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught invalid roland SysEx message!"); + return false; + } + } +#endif + + unsigned address = + (((unsigned)data[0] & 0x7F) << 16) | + (((unsigned)data[1] & 0x7F) << 8) | + (((unsigned)data[2] & 0x7F)); + unsigned target_channel = 0; + + /* F0 41 10 42 12 40 00 7F 00 41 F7 */ + + if((address & 0xFFF0FF) == 0x401015) // Turn channel 1 into percussion + { + address = 0x401015; + target_channel = data[1] & 0x0F; + } + + data += 3; + size -= 3; + + if(mode != RolandMode_Send) // don't have MIDI-Out reply ability + return false; + + // Mode Set + // F0 {41 10 42 12} {40 00 7F} {00 41} F7 + + // Custom drum channels + // F0 {41 10 42 12} {40 1 15} { } F7 + + switch((model << 24) | address) + { + case (RolandModel_GS << 24) | 0x00007F: // System Mode Set + { + if(size != 1 || (dev & 0xF0) != 0x10) + break; + unsigned mode = data[0] & 0x7F; + ADL_UNUSED(mode);//TODO: Hook this correctly! + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland System Mode Set: %02X", mode); + m_synthMode = Mode_GS; + realTime_ResetState(); + return true; + } + case (RolandModel_GS << 24) | 0x40007F: // Mode Set + { + if(size != 1 || (dev & 0xF0) != 0x10) + break; + unsigned value = data[0] & 0x7F; + ADL_UNUSED(value);//TODO: Hook this correctly! + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland Mode Set: %02X", value); + m_synthMode = Mode_GS; + realTime_ResetState(); + return true; + } + case (RolandModel_GS << 24) | 0x401015: // Percussion channel + { + if(size != 1 || (dev & 0xF0) != 0x10) + break; + if(m_midiChannels.size() < 16) + break; + unsigned value = data[0] & 0x7F; + const uint8_t channels_map[16] = + { + 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15 + }; + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, + "SysEx: Caught Roland Percussion set: %02X on channel %u (from %X)", + value, channels_map[target_channel], target_channel); + m_midiChannels[channels_map[target_channel]].is_xg_percussion = ((value == 0x01)) || ((value == 0x02)); + return true; + } + } + + return false; +} + +bool OPNMIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) +{ + bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; + if(size < 1 || !devicematch) + return false; + + unsigned model = data[0] & 0x7F; + ++data; + --size; + + switch((model << 8) | (dev & 0xF0)) + { + case (YamahaModel_XG << 8) | 0x10: // parameter change + { + if(size < 3) + break; + + unsigned address = + (((unsigned)data[0] & 0x7F) << 16) | + (((unsigned)data[1] & 0x7F) << 8) | + (((unsigned)data[2] & 0x7F)); + data += 3; + size -= 3; + + switch(address) + { + case 0x00007E: // XG System On + if(size != 1) + break; + unsigned value = data[0] & 0x7F; + ADL_UNUSED(value);//TODO: Hook this correctly! + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Yamaha XG System On: %02X", value); + m_synthMode = Mode_XG; + realTime_ResetState(); + return true; + } + + break; + } + } + + return false; } void OPNMIDIplay::realTime_panic() { - Panic(); - KillSustainingNotes(-1, -1); + panic(); + killSustainingNotes(-1, -1, OpnChannel::LocationData::Sustain_ANY); } +void OPNMIDIplay::realTime_deviceSwitch(size_t track, const char *data, size_t length) +{ + const std::string indata(data, length); + m_currentMidiDevice[track] = chooseDevice(indata); +} -void OPNMIDIplay::NoteUpdate(uint16_t MidCh, +size_t OPNMIDIplay::realTime_currentDevice(size_t track) +{ + if(m_currentMidiDevice.empty()) + return 0; + return m_currentMidiDevice[track]; +} + +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) +void OPNMIDIplay::AudioTick(uint32_t chipId, uint32_t rate) +{ + if(chipId != 0) // do first chip ticks only + return; + + uint32_t tickNumber = m_audioTickCounter++; + double timeDelta = 1.0 / rate; + + enum { portamentoInterval = 32 }; // for efficiency, set rate limit on pitch updates + + if(tickNumber % portamentoInterval == 0) + { + double portamentoDelta = timeDelta * portamentoInterval; + UpdateGlide(portamentoDelta); + } +} +#endif + +void OPNMIDIplay::noteUpdate(size_t midCh, OPNMIDIplay::MIDIchannel::activenoteiterator i, unsigned props_mask, int32_t select_adlchn) { MIDIchannel::NoteInfo &info = *i; - const int16_t tone = info.tone; + const int16_t noteTone = info.noteTone; + const double currentTone = info.currentTone; const uint8_t vol = info.vol; const size_t midiins = info.midiins; const opnInstMeta2 &ains = *info.ains; OpnChannel::Location my_loc; - my_loc.MidCh = MidCh; + my_loc.MidCh = static_cast(midCh); my_loc.note = info.note; + if(info.isBlank) + { + if(props_mask & Upd_Off) + m_midiChannels[midCh].activenotes_erase(i); + return; + } + for(unsigned ccount = 0, ctotal = info.chip_channels_count; ccount < ctotal; ccount++) { const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount]; @@ -1389,13 +1015,13 @@ void OPNMIDIplay::NoteUpdate(uint16_t MidCh, if(props_mask & Upd_Patch) { - opn.Patch(c, ins.ains); - OpnChannel::LocationData *d = ch[c].users_find_or_create(my_loc); + m_synth.setPatch(c, ins.ains); + OpnChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); if(d) { // inserts if necessary - d->sustained = false; - d->vibdelay = 0; + d->sustained = OpnChannel::LocationData::Sustain_None; + d->vibdelay_us = 0; d->fixed_sustain = (ains.ms_sound_kon == static_cast(opnNoteOnMaxTime)); - d->kon_time_until_neglible = ains.ms_sound_kon; + d->kon_time_until_neglible_us = 1000 * ains.ms_sound_kon; d->ins = ins; } } @@ -1411,25 +1037,27 @@ void OPNMIDIplay::NoteUpdate(uint16_t MidCh, if(props_mask & Upd_Off) // note off { - if(Ch[MidCh].sustain == 0) + if(m_midiChannels[midCh].sustain == 0) { - OpnChannel::LocationData *k = ch[c].users_find(my_loc); - - if(k) - ch[c].users_erase(k); + OpnChannel::LocationData *k = m_chipChannels[c].users_find(my_loc); + bool do_erase_user = (k && ((k->sustained & OpnChannel::LocationData::Sustain_Sostenuto) == 0)); + if(do_erase_user) + m_chipChannels[c].users_erase(k); if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, tone, (int)midiins, 0, 0.0); + hooks.onNote(hooks.onNote_userData, c, noteTone, (int)midiins, 0, 0.0); - if(ch[c].users_empty()) + if(do_erase_user && m_chipChannels[c].users_empty()) { - opn.NoteOff(c); + m_synth.noteOff(c); if(props_mask & Upd_Mute) // Mute the note { - opn.Touch_Real(c, 0); - ch[c].koff_time_until_neglible = 0; - } else { - ch[c].koff_time_until_neglible = ains.ms_sound_koff; + m_synth.touchNote(c, 0); + m_chipChannels[c].koff_time_until_neglible_us = 0; + } + else + { + m_chipChannels[c].koff_time_until_neglible_us = 1000 * int64_t(ains.ms_sound_koff); } } } @@ -1437,11 +1065,11 @@ void OPNMIDIplay::NoteUpdate(uint16_t MidCh, { // Sustain: Forget about the note, but don't key it off. // Also will avoid overwriting it very soon. - OpnChannel::LocationData *d = ch[c].users_find_or_create(my_loc); + OpnChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); if(d) - d->sustained = true; // note: not erased! + d->sustained |= OpnChannel::LocationData::Sustain_Pedal; // note: not erased! if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, tone, (int)midiins, -1, 0.0); + hooks.onNote(hooks.onNote_userData, c, noteTone, (int)midiins, -1, 0.0); } info.phys_erase_at(&ins); // decrements channel count @@ -1450,13 +1078,13 @@ void OPNMIDIplay::NoteUpdate(uint16_t MidCh, } if(props_mask & Upd_Pan) - opn.Pan(c, Ch[MidCh].panning); + m_synth.setPan(c, m_midiChannels[midCh].panning); if(props_mask & Upd_Volume) { - uint32_t volume; - bool is_percussion = (MidCh == 9) || Ch[MidCh].is_xg_percussion; - uint8_t brightness = is_percussion ? 127 : Ch[MidCh].brightness; + uint_fast32_t volume; + bool is_percussion = (midCh == 9) || m_midiChannels[midCh].is_xg_percussion; + uint_fast32_t brightness = is_percussion ? 127 : m_midiChannels[midCh].brightness; if(!m_setup.fullRangeBrightnessCC74) { @@ -1467,11 +1095,12 @@ void OPNMIDIplay::NoteUpdate(uint16_t MidCh, brightness *= 2; } - switch(opn.m_volumeScale) + switch(m_synth.m_volumeScale) { + default: case OPN2::VOLUME_Generic: { - volume = vol * Ch[MidCh].volume * Ch[MidCh].expression; + volume = vol * m_masterVolume * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression; /* If the channel has arpeggio, the effective volume of * *this* instrument is actually lower due to timesharing. * To compensate, add extra volume that corresponds to the @@ -1482,77 +1111,78 @@ void OPNMIDIplay::NoteUpdate(uint16_t MidCh, //volume = (int)(volume * std::sqrt( (double) ch[c].users.size() )); // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) - volume = volume > 8725 ? static_cast((std::log(static_cast(volume)) * (11.541561) + (0.5 - 104.22845)) * 2.0) : 0; + volume = volume > (8725 * 127) ? static_cast((std::log(static_cast(volume)) * 11.541560327111707 - 1.601379199767093e+02) * 2.0) : 0; // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) //opl.Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); - - opn.Touch_Real(c, volume, brightness); } break; - case OPN2::VOLUME_CMF: + case OPN2::VOLUME_NATIVE: { - volume = vol * Ch[MidCh].volume * Ch[MidCh].expression; - volume = volume * 127 / (2048383/*127 * 127 * 127*/); - opn.Touch_Real(c, volume, brightness); + volume = vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression; + //volume = volume * m_masterVolume / (127 * 127 * 127) / 2; + volume = (volume * m_masterVolume) / 4096766; } break; case OPN2::VOLUME_DMX: { - volume = 2 * ((Ch[MidCh].volume * Ch[MidCh].expression) * 127 / 16129) + 1; + volume = 2 * (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 16129) + 1; //volume = 2 * (Ch[MidCh].volume) + 1; - volume = (DMX_volume_mapping_table[vol] * volume) >> 9; - opn.Touch_Real(c, volume, brightness); + volume = (DMX_volume_mapping_table[(vol < 128) ? vol : 127] * volume) >> 9; + if(volume > 0) + volume += 64;//OPN has 0~127 range. As 0...63 is almost full silence, but at 64 to 127 is very closed to OPL3, just add 64. } break; case OPN2::VOLUME_APOGEE: { - volume = ((Ch[MidCh].volume * Ch[MidCh].expression) * 127 / 16129); + volume = (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 16129); volume = ((64 * (vol + 0x80)) * volume) >> 15; //volume = ((63 * (vol + 0x80)) * Ch[MidCh].volume) >> 15; - volume *= 2;//OPN has 0~127 range - opn.Touch_Real(c, volume, brightness); + if(volume > 0) + volume += 64;//OPN has 0~127 range. As 0...63 is almost full silence, but at 64 to 127 is very closed to OPL3, just add 64. } break; case OPN2::VOLUME_9X: { //volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume /** Ch[MidCh].expression*/) * 127 / 16129 /*2048383*/) >> 2)]; - volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume * Ch[MidCh].expression) * 127 / 2048383) >> 2)]; + volume = 63 - W9X_volume_mapping_table[((vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 2048383) >> 2)]; //volume = W9X_volume_mapping_table[vol >> 2] + volume; - volume *= 2;//OPN has 0~127 range - opn.Touch_Real(c, volume, brightness); + if(volume > 0) + volume += 64;//OPN has 0~127 range. As 0...63 is almost full silence, but at 64 to 127 is very closed to OPL3, just add 64. } break; } + m_synth.touchNote(c, static_cast(volume), static_cast(brightness)); + /* DEBUG ONLY!!! - static uint32_t max = 0; + static uint32_t max = 0; - if(volume == 0) - max = 0; + if(volume == 0) + max = 0; - if(volume > max) - max = volume; + if(volume > max) + max = volume; - printf("%d\n", max); - fflush(stdout); - */ + printf("%d\n", max); + fflush(stdout); + */ } if(props_mask & Upd_Pitch) { - OpnChannel::LocationData *d = ch[c].users_find(my_loc); + OpnChannel::LocationData *d = m_chipChannels[c].users_find(my_loc); // Don't bend a sustained note - if(!d || !d->sustained) + if(!d || (d->sustained == OpnChannel::LocationData::Sustain_None)) { - double midibend = Ch[MidCh].bend * Ch[MidCh].bendsense; + double midibend = m_midiChannels[midCh].bend * m_midiChannels[midCh].bendsense; double bend = midibend + ins.ains.finetune; double phase = 0.0; - uint8_t vibrato = std::max(Ch[MidCh].vibrato, Ch[MidCh].aftertouch); + uint8_t vibrato = std::max(m_midiChannels[midCh].vibrato, m_midiChannels[midCh].aftertouch); vibrato = std::max(vibrato, i->vibrato); if((ains.flags & opnInstMeta::Flag_Pseudo8op) && ins.ains == ains.opn[1]) @@ -1560,349 +1190,35 @@ void OPNMIDIplay::NoteUpdate(uint16_t MidCh, phase = ains.fine_tune;//0.125; // Detune the note slightly (this is what Doom does) } - if(vibrato && (!d || d->vibdelay >= Ch[MidCh].vibdelay)) - bend += static_cast(vibrato) * Ch[MidCh].vibdepth * std::sin(Ch[MidCh].vibpos); + if(vibrato && (!d || d->vibdelay_us >= m_midiChannels[midCh].vibdelay_us)) + bend += static_cast(vibrato) * m_midiChannels[midCh].vibdepth * std::sin(m_midiChannels[midCh].vibpos); #define BEND_COEFFICIENT 321.88557 - opn.NoteOn(c, BEND_COEFFICIENT * std::exp(0.057762265 * (static_cast(tone) + bend + phase))); + m_synth.noteOn(c, BEND_COEFFICIENT * std::exp(0.057762265 * (currentTone + bend + phase))); #undef BEND_COEFFICIENT if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, tone, (int)midiins, vol, midibend); + hooks.onNote(hooks.onNote_userData, c, noteTone, (int)midiins, vol, midibend); } } } if(info.chip_channels_count == 0) - Ch[MidCh].activenotes_erase(i); + { + if(i->glideRate != HUGE_VAL) + --m_midiChannels[midCh].gliding_note_count; + m_midiChannels[midCh].activenotes_erase(i); + } } -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER -bool OPNMIDIplay::ProcessEventsNew(bool isSeek) +void OPNMIDIplay::noteUpdateAll(size_t midCh, unsigned props_mask) { - if(CurrentPositionNew.track.size() == 0) - atEnd = true;//No MIDI track data to play - if(atEnd) - return false;//No more events in the queue - - loopEnd = false; - const size_t TrackCount = CurrentPositionNew.track.size(); - const PositionNew RowBeginPosition(CurrentPositionNew); - - #ifdef DEBUG_TIME_CALCULATION - double maxTime = 0.0; - #endif - - for(size_t tk = 0; tk < TrackCount; ++tk) + for(MIDIchannel::activenoteiterator + i = m_midiChannels[midCh].activenotes_begin(); i;) { - PositionNew::TrackInfo &track = CurrentPositionNew.track[tk]; - if((track.status >= 0) && (track.delay <= 0)) - { - //Check is an end of track has been reached - if(track.pos == trackDataNew[tk].end()) - { - track.status = -1; - break; - } - - // Handle event - for(size_t i = 0; i < track.pos->events.size(); i++) - { - const MidiEvent &evt = track.pos->events[i]; - #ifdef ENABLE_BEGIN_SILENCE_SKIPPING - if(!CurrentPositionNew.began && (evt.type == MidiEvent::T_NOTEON)) - CurrentPositionNew.began = true; - #endif - if(isSeek && (evt.type == MidiEvent::T_NOTEON)) - continue; - HandleEvent(tk, evt, track.status); - if(loopEnd) - break;//Stop event handling on catching loopEnd event! - } - - #ifdef DEBUG_TIME_CALCULATION - if(maxTime < track.pos->time) - maxTime = track.pos->time; - #endif - // Read next event time (unless the track just ended) - if(track.status >= 0) - { - track.delay += track.pos->delay; - track.pos++; - } - } + MIDIchannel::activenoteiterator j(i++); + noteUpdate(midCh, j, props_mask); } - - #ifdef DEBUG_TIME_CALCULATION - std::fprintf(stdout, " \r"); - std::fprintf(stdout, "Time: %10f; Audio: %10f\r", maxTime, CurrentPositionNew.absTimePosition); - std::fflush(stdout); - #endif - - // Find shortest delay from all track - uint64_t shortest = 0; - bool shortest_no = true; - - for(size_t tk = 0; tk < TrackCount; ++tk) - { - PositionNew::TrackInfo &track = CurrentPositionNew.track[tk]; - if((track.status >= 0) && (shortest_no || track.delay < shortest)) - { - shortest = track.delay; - shortest_no = false; - } - } - - //if(shortest > 0) UI.PrintLn("shortest: %ld", shortest); - - // Schedule the next playevent to be processed after that delay - for(size_t tk = 0; tk < TrackCount; ++tk) - CurrentPositionNew.track[tk].delay -= shortest; - - fraction t = shortest * Tempo; - - #ifdef ENABLE_BEGIN_SILENCE_SKIPPING - if(CurrentPositionNew.began) - #endif - CurrentPositionNew.wait += t.value(); - - //if(shortest > 0) UI.PrintLn("Delay %ld (%g)", shortest, (double)t.valuel()); - if(loopStart) - { - LoopBeginPositionNew = RowBeginPosition; - loopStart = false; - } - - if(shortest_no || loopEnd) - { - //Loop if song end or loop end point has reached - loopEnd = false; - shortest = 0; - if(!m_setup.loopingIsEnabled) - { - atEnd = true; //Don't handle events anymore - CurrentPositionNew.wait += postSongWaitDelay;//One second delay until stop playing - return true;//We have caugh end here! - } - CurrentPositionNew = LoopBeginPositionNew; - } - - return true;//Has events in queue } -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER -OPNMIDIplay::MidiEvent OPNMIDIplay::parseEvent(uint8_t **pptr, uint8_t *end, int &status) -{ - uint8_t *&ptr = *pptr; - OPNMIDIplay::MidiEvent evt; - - if(ptr + 1 > end) - { - //When track doesn't ends on the middle of event data, it's must be fine - evt.type = MidiEvent::T_SPECIAL; - evt.subtype = MidiEvent::ST_ENDTRACK; - return evt; - } - - unsigned char byte = *(ptr++); - bool ok = false; - - if(byte == MidiEvent::T_SYSEX || byte == MidiEvent::T_SYSEX2)// Ignore SysEx - { - uint64_t length = ReadVarLenEx(pptr, end, ok); - if(!ok || (ptr + length > end)) - { - errorString += "parseEvent: Can't read SysEx event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - ptr += (size_t)length; - return evt; - } - - if(byte == MidiEvent::T_SPECIAL) - { - // Special event FF - uint8_t evtype = *(ptr++); - uint64_t length = ReadVarLenEx(pptr, end, ok); - if(!ok || (ptr + length > end)) - { - errorString += "parseEvent: Can't read Special event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - std::string data(length ? (const char *)ptr : 0, (size_t)length); - ptr += (size_t)length; - - evt.type = byte; - evt.subtype = evtype; - evt.data.insert(evt.data.begin(), data.begin(), data.end()); - -#if 0 /* Print all tempo events */ - if(evt.subtype == MidiEvent::ST_TEMPOCHANGE) - { - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Temp Change: %02X%02X%02X", evt.data[0], evt.data[1], evt.data[2]); - } -#endif - - /* TODO: Store those meta-strings separately and give ability to read them - * by external functions (to display song title and copyright in the player) */ - if(evt.subtype == MidiEvent::ST_COPYRIGHT) - { - if(musCopyright.empty()) - { - musCopyright = std::string((const char *)evt.data.data(), evt.data.size()); - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Music copyright: %s", musCopyright.c_str()); - } - else if(hooks.onDebugMessage) - { - std::string str((const char *)evt.data.data(), evt.data.size()); - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Extra copyright event: %s", str.c_str()); - } - } - else if(evt.subtype == MidiEvent::ST_SQTRKTITLE) - { - if(musTitle.empty()) - { - musTitle = std::string((const char *)evt.data.data(), evt.data.size()); - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Music title: %s", musTitle.c_str()); - } - else if(hooks.onDebugMessage) - { - //TODO: Store track titles and associate them with each track and make API to retreive them - std::string str((const char *)evt.data.data(), evt.data.size()); - musTrackTitles.push_back(str); - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Track title: %s", str.c_str()); - } - } - else if(evt.subtype == MidiEvent::ST_INSTRTITLE) - { - if(hooks.onDebugMessage) - { - std::string str((const char *)evt.data.data(), evt.data.size()); - hooks.onDebugMessage(hooks.onDebugMessage_userData, "Instrument: %s", str.c_str()); - } - } - else if(evt.subtype == MidiEvent::ST_MARKER) - { - //To lower - for(size_t i = 0; i < data.size(); i++) - { - if(data[i] <= 'Z' && data[i] >= 'A') - data[i] = data[i] - ('Z' - 'z'); - } - - if(data == "loopstart") - { - //Return a custom Loop Start event instead of Marker - evt.subtype = MidiEvent::ST_LOOPSTART; - evt.data.clear();//Data is not needed - return evt; - } - - if(data == "loopend") - { - //Return a custom Loop End event instead of Marker - evt.subtype = MidiEvent::ST_LOOPEND; - evt.data.clear();//Data is not needed - return evt; - } - } - - if(evtype == MidiEvent::ST_ENDTRACK) - status = -1;//Finalize track - - return evt; - } - - // Any normal event (80..EF) - if(byte < 0x80) - { - byte = static_cast(status | 0x80); - ptr--; - } - - //Sys Com Song Select(Song #) [0-127] - if(byte == MidiEvent::T_SYSCOMSNGSEL) - { - if(ptr + 1 > end) - { - errorString += "parseEvent: Can't read System Command Song Select event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - evt.type = byte; - evt.data.push_back(*(ptr++)); - return evt; - } - - //Sys Com Song Position Pntr [LSB, MSB] - if(byte == MidiEvent::T_SYSCOMSPOSPTR) - { - if(ptr + 2 > end) - { - errorString += "parseEvent: Can't read System Command Position Pointer event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - evt.type = byte; - evt.data.push_back(*(ptr++)); - evt.data.push_back(*(ptr++)); - return evt; - } - - uint8_t midCh = byte & 0x0F, evType = (byte >> 4) & 0x0F; - status = byte; - evt.channel = midCh; - evt.type = evType; - - switch(evType) - { - case MidiEvent::T_NOTEOFF://2 byte length - case MidiEvent::T_NOTEON: - case MidiEvent::T_NOTETOUCH: - case MidiEvent::T_CTRLCHANGE: - case MidiEvent::T_WHEEL: - if(ptr + 2 > end) - { - errorString += "parseEvent: Can't read regular 2-byte event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - - evt.data.push_back(*(ptr++)); - evt.data.push_back(*(ptr++)); - - if((evType == MidiEvent::T_NOTEON) && (evt.data[1] == 0)) - evt.type = MidiEvent::T_NOTEOFF; // Note ON with zero velocity is Note OFF! - //111'th loopStart controller (RPG Maker and others) - else if((evType == MidiEvent::T_CTRLCHANGE) && (evt.data[0] == 111)) - { - //Change event type to custom Loop Start event and clear data - evt.type = MidiEvent::T_SPECIAL; - evt.subtype = MidiEvent::ST_LOOPSTART; - evt.data.clear(); - } - - return evt; - case MidiEvent::T_PATCHCHANGE://1 byte length - case MidiEvent::T_CHANAFTTOUCH: - if(ptr + 1 > end) - { - errorString += "parseEvent: Can't read regular 1-byte event - Unexpected end of track data.\n"; - evt.isValid = 0; - return evt; - } - evt.data.push_back(*(ptr++)); - return evt; - } - - return evt; -} -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER const std::string &OPNMIDIplay::getErrorString() { @@ -1914,182 +1230,33 @@ void OPNMIDIplay::setErrorString(const std::string &err) errorStringOut = err; } -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER -void OPNMIDIplay::HandleEvent(size_t tk, const OPNMIDIplay::MidiEvent &evt, int &status) +int64_t OPNMIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const { - if(hooks.onEvent) + const OpnChannel &chan = m_chipChannels[c]; + int64_t koff_ms = chan.koff_time_until_neglible_us / 1000; + int64_t s = -koff_ms; + + // Rate channel with a releasing note + if(s < 0 && chan.users_empty()) { - hooks.onEvent(hooks.onEvent_userData, - evt.type, - evt.subtype, - evt.channel, - evt.data.data(), - evt.data.size()); + s -= 40000; + // If it's same instrument, better chance to get it when no free channels + if(chan.recent_ins == ins) + s = (m_synth.m_musicMode == OPN2::MODE_CMF) ? 0 : -koff_ms; + return s; } - if(evt.type == MidiEvent::T_SYSEX || evt.type == MidiEvent::T_SYSEX2) // Ignore SysEx - { - //std::string data( length?(const char*) &TrackData[tk][CurrentPosition.track[tk].ptr]:0, length ); - //UI.PrintLn("SysEx %02X: %u bytes", byte, length/*, data.c_str()*/); - return; - } - - if(evt.type == MidiEvent::T_SPECIAL) - { - // Special event FF - uint8_t evtype = evt.subtype; - uint64_t length = (uint64_t)evt.data.size(); - std::string data(length ? (const char *)evt.data.data() : 0, (size_t)length); - - if(evtype == MidiEvent::ST_ENDTRACK)//End Of Track - { - status = -1; - return; - } - - if(evtype == MidiEvent::ST_TEMPOCHANGE)//Tempo change - { - Tempo = InvDeltaTicks * fraction(ReadBEint(evt.data.data(), evt.data.size())); - return; - } - - if(evtype == MidiEvent::ST_MARKER)//Meta event - { - //Do nothing! :-P - return; - } - - if(evtype == MidiEvent::ST_DEVICESWITCH) - { - current_device[tk] = ChooseDevice(data); - return; - } - - //if(evtype >= 1 && evtype <= 6) - // UI.PrintLn("Meta %d: %s", evtype, data.c_str()); - - //Turn on Loop handling when loop is enabled - if(m_setup.loopingIsEnabled && !invalidLoop) - { - if(evtype == MidiEvent::ST_LOOPSTART) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib - { - loopStart = true; - return; - } - - if(evtype == MidiEvent::ST_LOOPEND) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib - { - loopEnd = true; - return; - } - } - - //if(evtype == MidiEvent::ST_RAWOPL) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib - //{ - // uint8_t i = static_cast(data[0]), v = static_cast(data[1]); - // if((i & 0xF0) == 0xC0) - // v |= 0x30; - // //std::printf("OPL poke %02X, %02X\n", i, v); - // //std::fflush(stdout); - // opl.PokeN(0, i, v); - // return; - //} - - return; - } - - // Any normal event (80..EF) - // if(evt.type < 0x80) - // { - // byte = static_cast(CurrentPosition.track[tk].status | 0x80); - // CurrentPosition.track[tk].ptr--; - // } - - if(evt.type == MidiEvent::T_SYSCOMSNGSEL || - evt.type == MidiEvent::T_SYSCOMSPOSPTR) - return; - - /*UI.PrintLn("@%X Track %u: %02X %02X", - CurrentPosition.track[tk].ptr-1, (unsigned)tk, byte, - TrackData[tk][CurrentPosition.track[tk].ptr]);*/ - uint8_t midCh = evt.channel;//byte & 0x0F, EvType = byte >> 4; - midCh += (uint8_t)current_device[tk]; - status = evt.type; - - switch(evt.type) - { - case MidiEvent::T_NOTEOFF: // Note off - { - uint8_t note = evt.data[0]; - realTime_NoteOff(midCh, note); - break; - } - - case MidiEvent::T_NOTEON: // Note on - { - uint8_t note = evt.data[0]; - uint8_t vol = evt.data[1]; - /*if(*/ realTime_NoteOn(midCh, note, vol); /*)*/ - //CurrentPosition.began = true; - break; - } - - case MidiEvent::T_NOTETOUCH: // Note touch - { - uint8_t note = evt.data[0]; - uint8_t vol = evt.data[1]; - realTime_NoteAfterTouch(midCh, note, vol); - break; - } - - case MidiEvent::T_CTRLCHANGE: // Controller change - { - uint8_t ctrlno = evt.data[0]; - uint8_t value = evt.data[1]; - realTime_Controller(midCh, ctrlno, value); - break; - } - - case MidiEvent::T_PATCHCHANGE: // Patch change - realTime_PatchChange(midCh, evt.data[0]); - break; - - case MidiEvent::T_CHANAFTTOUCH: // Channel after-touch - { - // TODO: Verify, is this correct action? - uint8_t vol = evt.data[0]; - realTime_ChannelAfterTouch(midCh, vol); - break; - } - - case MidiEvent::T_WHEEL: // Wheel/pitch bend - { - uint8_t a = evt.data[0]; - uint8_t b = evt.data[1]; - realTime_PitchBend(midCh, b, a); - break; - } - } -} -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER - -int64_t OPNMIDIplay::CalculateAdlChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins, uint16_t) const -{ - int64_t s = -ch[c].koff_time_until_neglible; - // Same midi-instrument = some stability - //if(c == MidCh) s += 4; - for (OpnChannel::LocationData *j = ch[c].users_first; j; j = j->next) + for(OpnChannel::LocationData *j = chan.users_first; j; j = j->next) { - s -= 4000; + s -= 4000000; - if(!j->sustained) - s -= j->kon_time_until_neglible; - else - s -= (j->kon_time_until_neglible / 2); + int64_t kon_ms = j->kon_time_until_neglible_us / 1000; + s -= (j->sustained == OpnChannel::LocationData::Sustain_None) ? + kon_ms : (kon_ms / 2); MIDIchannel::activenoteiterator - k = const_cast(Ch[j->loc.MidCh]).activenotes_find(j->loc.note); + k = const_cast(m_midiChannels[j->loc.MidCh]).activenotes_find(j->loc.note); if(k) { @@ -2098,21 +1265,13 @@ int64_t OPNMIDIplay::CalculateAdlChannelGoodness(size_t c, const MIDIchannel::No { s += 300; // Arpeggio candidate = even better - if(j->vibdelay < 70 - || j->kon_time_until_neglible > 20000) - s += 0; + if(j->vibdelay_us < 70000 + || j->kon_time_until_neglible_us > 20000000) + s += 10; } // Percussion is inferior to melody - s += 50 * (int64_t)(k->midiins / 128); - /* - if(k->second.midiins >= 25 - && k->second.midiins < 40 - && j->second.ins != ins) - { - s -= 14000; // HACK: Don't clobber the bass or the guitar - } - */ + s += k->isPercussion ? 50 : 0; } // If there is another channel to which this note @@ -2129,8 +1288,8 @@ int64_t OPNMIDIplay::CalculateAdlChannelGoodness(size_t c, const MIDIchannel::No // for(OpnChannel::LocationData *m = ch[c2].users_first; m; m = m->next) // { -// if(m->sustained) continue; -// if(m->vibdelay >= 200) continue; +// if(m->sustained != OpnChannel::LocationData::Sustain_None) continue; +// if(m->vibdelay >= 200000) continue; // if(m->ins != j->second.ins) continue; // n_evacuation_stations += 1; // } @@ -2143,12 +1302,12 @@ int64_t OPNMIDIplay::CalculateAdlChannelGoodness(size_t c, const MIDIchannel::No } -void OPNMIDIplay::PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins) +void OPNMIDIplay::prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins) { - if(ch[c].users_empty()) return; // Nothing to do + if(m_chipChannels[c].users_empty()) return; // Nothing to do //bool doing_arpeggio = false; - for(OpnChannel::LocationData *jnext = ch[c].users_first; jnext;) + for(OpnChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) { OpnChannel::LocationData *j = jnext; jnext = jnext->next; @@ -2158,11 +1317,11 @@ void OPNMIDIplay::PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteI // Collision: Kill old note, // UNLESS we're going to do arpeggio MIDIchannel::activenoteiterator i - (Ch[j->loc.MidCh].activenotes_ensure_find(j->loc.note)); + (m_midiChannels[j->loc.MidCh].activenotes_ensure_find(j->loc.note)); // Check if we can do arpeggio. - if((j->vibdelay < 70 - || j->kon_time_until_neglible > 20000) + if((j->vibdelay_us < 70000 + || j->kon_time_until_neglible_us > 20000000) && j->ins == ins) { // Do arpeggio together with this note. @@ -2170,7 +1329,7 @@ void OPNMIDIplay::PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteI continue; } - KillOrEvacuate(c, j, i); + killOrEvacuate(c, j, i); // ^ will also erase j from ch[c].users. } } @@ -2178,62 +1337,64 @@ void OPNMIDIplay::PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteI // Kill all sustained notes on this channel // Don't keep them for arpeggio, because arpeggio requires // an intact "activenotes" record. This is a design flaw. - KillSustainingNotes(-1, static_cast(c)); + killSustainingNotes(-1, static_cast(c), OpnChannel::LocationData::Sustain_ANY); // Keyoff the channel so that it can be retriggered, // unless the new note will be introduced as just an arpeggio. - if(ch[c].users_empty()) - opn.NoteOff(c); + if(m_chipChannels[c].users_empty()) + m_synth.noteOff(c); } -void OPNMIDIplay::KillOrEvacuate(size_t from_channel, +void OPNMIDIplay::killOrEvacuate(size_t from_channel, OpnChannel::LocationData *j, OPNMIDIplay::MIDIchannel::activenoteiterator i) { + uint32_t maxChannels = OPN_MAX_CHIPS * 6; + // Before killing the note, check if it can be // evacuated to another channel as an arpeggio // instrument. This helps if e.g. all channels // are full of strings and we want to do percussion. // FIXME: This does not care about four-op entanglements. - for(uint32_t c = 0; c < opn.NumChannels; ++c) + for(uint32_t c = 0; c < m_synth.m_numChannels; ++c) { uint16_t cs = static_cast(c); - if(c > std::numeric_limits::max()) + if(c >= maxChannels) break; if(c == from_channel) continue; //if(opn.four_op_category[c] != opn.four_op_category[from_channel]) // continue; - OpnChannel &adlch = ch[c]; + OpnChannel &adlch = m_chipChannels[c]; if(adlch.users_size == OpnChannel::users_max) continue; // no room for more arpeggio on channel for(OpnChannel::LocationData *m = adlch.users_first; m; m = m->next) { - if(m->vibdelay >= 200 - && m->kon_time_until_neglible < 10000) continue; + if(m->vibdelay_us >= 200000 + && m->kon_time_until_neglible_us < 10000000) continue; if(m->ins != j->ins) continue; if(hooks.onNote) { hooks.onNote(hooks.onNote_userData, (int)from_channel, - i->tone, + i->noteTone, (int)i->midiins, 0, 0.0); hooks.onNote(hooks.onNote_userData, (int)c, - i->tone, + i->noteTone, (int)i->midiins, i->vol, 0.0); } i->phys_erase(static_cast(from_channel)); i->phys_ensure_find_or_create(cs)->assign(j->ins); - if(!ch[cs].users_insert(*j)) + if(!m_chipChannels[cs].users_insert(*j)) assert(false); - ch[from_channel].users_erase(j); + m_chipChannels[from_channel].users_erase(j); return; } } @@ -2246,24 +1407,24 @@ void OPNMIDIplay::KillOrEvacuate(size_t from_channel, ins );*/ // Kill it - NoteUpdate(j->loc.MidCh, + noteUpdate(j->loc.MidCh, i, Upd_Off, static_cast(from_channel)); } -void OPNMIDIplay::Panic() +void OPNMIDIplay::panic() { - for(uint8_t chan = 0; chan < Ch.size(); chan++) + for(uint8_t chan = 0; chan < m_midiChannels.size(); chan++) { for(uint8_t note = 0; note < 128; note++) realTime_NoteOff(chan, note); } } -void OPNMIDIplay::KillSustainingNotes(int32_t MidCh, int32_t this_adlchn) +void OPNMIDIplay::killSustainingNotes(int32_t midCh, int32_t this_adlchn, uint32_t sustain_type) { - uint32_t first = 0, last = opn.NumChannels; + uint32_t first = 0, last = m_synth.m_numChannels; if(this_adlchn >= 0) { @@ -2271,57 +1432,87 @@ void OPNMIDIplay::KillSustainingNotes(int32_t MidCh, int32_t this_adlchn) last = first + 1; } - for(unsigned c = first; c < last; ++c) + for(uint32_t c = first; c < last; ++c) { - if(ch[c].users_empty()) continue; // Nothing to do + if(m_chipChannels[c].users_empty()) + continue; // Nothing to do - for(OpnChannel::LocationData *jnext = ch[c].users_first; jnext;) + for(OpnChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) { OpnChannel::LocationData *j = jnext; jnext = jnext->next; - if((MidCh < 0 || j->loc.MidCh == MidCh) - && j->sustained) + if((midCh < 0 || j->loc.MidCh == midCh) + && ((j->sustained & sustain_type) != 0)) { int midiins = '?'; if(hooks.onNote) hooks.onNote(hooks.onNote_userData, (int)c, j->loc.note, midiins, 0, 0.0); - ch[c].users_erase(j); + j->sustained &= ~sustain_type; + if(j->sustained == OpnChannel::LocationData::Sustain_None) + m_chipChannels[c].users_erase(j);//Remove only when note is clean from any holders } } // Keyoff the channel, if there are no users left. - if(ch[c].users_empty()) - opn.NoteOff(c); + if(m_chipChannels[c].users_empty()) + m_synth.noteOff(c); } } -void OPNMIDIplay::SetRPN(unsigned MidCh, unsigned value, bool MSB) +void OPNMIDIplay::markSostenutoNotes(int32_t midCh) { - bool nrpn = Ch[MidCh].nrpn; - unsigned addr = Ch[MidCh].lastmrpn * 0x100 + Ch[MidCh].lastlrpn; + uint32_t first = 0, last = m_synth.m_numChannels; + for(uint32_t c = first; c < last; ++c) + { + if(m_chipChannels[c].users_empty()) + continue; // Nothing to do + + for(OpnChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) + { + OpnChannel::LocationData *j = jnext; + jnext = jnext->next; + if((j->loc.MidCh == midCh) && (j->sustained == OpnChannel::LocationData::Sustain_None)) + j->sustained |= OpnChannel::LocationData::Sustain_Sostenuto; + } + } +} + +void OPNMIDIplay::setRPN(size_t midCh, unsigned value, bool MSB) +{ + bool nrpn = m_midiChannels[midCh].nrpn; + unsigned addr = m_midiChannels[midCh].lastmrpn * 0x100 + m_midiChannels[midCh].lastlrpn; switch(addr + nrpn * 0x10000 + MSB * 0x20000) { case 0x0000 + 0*0x10000 + 1*0x20000: // Pitch-bender sensitivity - Ch[MidCh].bendsense_msb = value; - Ch[MidCh].updateBendSensitivity(); + m_midiChannels[midCh].bendsense_msb = value; + m_midiChannels[midCh].updateBendSensitivity(); break; case 0x0000 + 0*0x10000 + 0*0x20000: // Pitch-bender sensitivity LSB - Ch[MidCh].bendsense_lsb = value; - Ch[MidCh].updateBendSensitivity(); + m_midiChannels[midCh].bendsense_lsb = value; + m_midiChannels[midCh].updateBendSensitivity(); break; case 0x0108 + 1*0x10000 + 1*0x20000: // Vibrato speed - if(value == 64) Ch[MidCh].vibspeed = 1.0; - else if(value < 100) Ch[MidCh].vibspeed = 1.0 / (1.6e-2 * (value ? value : 1)); - else Ch[MidCh].vibspeed = 1.0 / (0.051153846 * value - 3.4965385); - Ch[MidCh].vibspeed *= 2 * 3.141592653 * 5.0; + if((m_synthMode & Mode_XG) != 0) // Vibrato speed + { + if(value == 64) m_midiChannels[midCh].vibspeed = 1.0; + else if(value < 100) m_midiChannels[midCh].vibspeed = 1.0 / (1.6e-2 * (value ? value : 1)); + else m_midiChannels[midCh].vibspeed = 1.0 / (0.051153846 * value - 3.4965385); + m_midiChannels[midCh].vibspeed *= 2 * 3.141592653 * 5.0; + } break; - case 0x0109 + 1*0x10000 + 1*0x20000: // Vibrato depth - Ch[MidCh].vibdepth = ((value - 64) * 0.15) * 0.01; + case 0x0109 + 1*0x10000 + 1*0x20000: + if((m_synthMode & Mode_XG) != 0) // Vibrato depth + { + m_midiChannels[midCh].vibdepth = (((int)value - 64) * 0.15) * 0.01; + } break; - case 0x010A + 1*0x10000 + 1*0x20000: // Vibrato delay in millisecons - Ch[MidCh].vibdelay = value ? int64_t(0.2092 * std::exp(0.0795 * (double)value)) : 0; + case 0x010A + 1*0x10000 + 1*0x20000: + if((m_synthMode & Mode_XG) != 0) // Vibrato delay in millisecons + { + m_midiChannels[midCh].vibdelay_us = value ? int64_t(209.2 * std::exp(0.0795 * (double)value)) : 0; + } break; default:/* UI.PrintLn("%s %04X <- %d (%cSB) (ch %u)", "NRPN"+!nrpn, addr, value, "LM"[MSB], MidCh);*/ @@ -2329,67 +1520,56 @@ void OPNMIDIplay::SetRPN(unsigned MidCh, unsigned value, bool MSB) } } -//void MIDIplay::UpdatePortamento(unsigned MidCh) -//{ -// // mt = 2^(portamento/2048) * (1.0 / 5000.0) -// /* -// double mt = std::exp(0.00033845077 * Ch[MidCh].portamento); -// NoteUpdate_All(MidCh, Upd_Pitch); -// */ -// //UI.PrintLn("Portamento %u: %u (unimplemented)", MidCh, Ch[MidCh].portamento); -//} - -void OPNMIDIplay::NoteUpdate_All(uint16_t MidCh, unsigned props_mask) +void OPNMIDIplay::updatePortamento(size_t midCh) { - for(MIDIchannel::activenoteiterator - i = Ch[MidCh].activenotes_begin(); i;) - { - MIDIchannel::activenoteiterator j(i++); - NoteUpdate(MidCh, j, props_mask); - } + double rate = HUGE_VAL; + uint16_t midival = m_midiChannels[midCh].portamento; + if(m_midiChannels[midCh].portamentoEnable && midival > 0) + rate = 350.0 * std::pow(2.0, -0.062 * (1.0 / 128) * midival); + m_midiChannels[midCh].portamentoRate = rate; } -void OPNMIDIplay::NoteOff(uint16_t MidCh, uint8_t note) +void OPNMIDIplay::noteOff(size_t midCh, uint8_t note) { MIDIchannel::activenoteiterator - i = Ch[MidCh].activenotes_find(note); + i = m_midiChannels[midCh].activenotes_find(note); if(i) - NoteUpdate(MidCh, i, Upd_Off); + noteUpdate(midCh, i, Upd_Off); } -void OPNMIDIplay::UpdateVibrato(double amount) +void OPNMIDIplay::updateVibrato(double amount) { - for(size_t a = 0, b = Ch.size(); a < b; ++a) + for(size_t a = 0, b = m_midiChannels.size(); a < b; ++a) { - if(Ch[a].hasVibrato() && !Ch[a].activenotes_empty()) + if(m_midiChannels[a].hasVibrato() && !m_midiChannels[a].activenotes_empty()) { - NoteUpdate_All(static_cast(a), Upd_Pitch); - Ch[a].vibpos += amount * Ch[a].vibspeed; + noteUpdateAll(static_cast(a), Upd_Pitch); + m_midiChannels[a].vibpos += amount * m_midiChannels[a].vibspeed; } else - Ch[a].vibpos = 0.0; + m_midiChannels[a].vibpos = 0.0; } } -uint64_t OPNMIDIplay::ChooseDevice(const std::string &name) +size_t OPNMIDIplay::chooseDevice(const std::string &name) { - std::map::iterator i = devices.find(name); + std::map::iterator i = m_midiDevices.find(name); - if(i != devices.end()) + if(i != m_midiDevices.end()) return i->second; - size_t n = devices.size() * 16; - devices.insert(std::make_pair(name, n)); - Ch.resize(n + 16); + size_t n = m_midiDevices.size() * 16; + m_midiDevices.insert(std::make_pair(name, n)); + m_midiChannels.resize(n + 16); return n; } -void OPNMIDIplay::UpdateArpeggio(double) // amount = amount of time passed +void OPNMIDIplay::updateArpeggio(double) // amount = amount of time passed { // If there is an adlib channel that has multiple notes // simulated on the same channel, arpeggio them. @@ -2415,17 +1595,17 @@ void OPNMIDIplay::UpdateArpeggio(double) // amount = amount of time passed ++m_arpeggioCounter; - for(uint32_t c = 0; c < opn.NumChannels; ++c) + for(uint32_t c = 0; c < m_synth.m_numChannels; ++c) { retry_arpeggio: if(c > uint32_t(std::numeric_limits::max())) break; - size_t n_users = ch[c].users_size; + size_t n_users = m_chipChannels[c].users_size; if(n_users > 1) { - OpnChannel::LocationData *i = ch[c].users_first; + OpnChannel::LocationData *i = m_chipChannels[c].users_first; size_t rate_reduction = 3; if(n_users >= 3) @@ -2438,21 +1618,21 @@ retry_arpeggio: n = 0; n < count; ++n) i = i->next; - if(i->sustained == false) + if(i->sustained == OpnChannel::LocationData::Sustain_None) { - if(i->kon_time_until_neglible <= 0l) + if(i->kon_time_until_neglible_us <= 0) { - NoteUpdate( + noteUpdate( i->loc.MidCh, - Ch[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), + m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), Upd_Off, static_cast(c)); goto retry_arpeggio; } - NoteUpdate( + noteUpdate( i->loc.MidCh, - Ch[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), + m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), Upd_Pitch | Upd_Volume | Upd_Pan, static_cast(c)); } @@ -2460,6 +1640,76 @@ retry_arpeggio: } } +void OPNMIDIplay::updateGlide(double amount) +{ + size_t num_channels = m_midiChannels.size(); + + for(size_t channel = 0; channel < num_channels; ++channel) + { + MIDIchannel &midiChan = m_midiChannels[channel]; + if(midiChan.gliding_note_count == 0) + continue; + + for(MIDIchannel::activenoteiterator it = midiChan.activenotes_begin(); + it; ++it) + { + double finalTone = it->noteTone; + double previousTone = it->currentTone; + + bool directionUp = previousTone < finalTone; + double toneIncr = amount * (directionUp ? +it->glideRate : -it->glideRate); + + double currentTone = previousTone + toneIncr; + bool glideFinished = !(directionUp ? (currentTone < finalTone) : (currentTone > finalTone)); + currentTone = glideFinished ? finalTone : currentTone; + + if(currentTone != previousTone) + { + it->currentTone = currentTone; + noteUpdate(static_cast(channel), it, Upd_Pitch); + } + } + } +} + +void OPNMIDIplay::describeChannels(char *str, char *attr, size_t size) +{ + if (!str || size <= 0) + return; + + OPN2 &synth = m_synth; + uint32_t numChannels = synth.m_numChannels; + + uint32_t index = 0; + while(index < numChannels && index < size - 1) + { + const OpnChannel &adlChannel = m_chipChannels[index]; + + OpnChannel::LocationData *loc = adlChannel.users_first; + if(!loc) // off + { + str[index] = '-'; + } + else if(loc->next) // arpeggio + { + str[index] = '@'; + } + else // on + { + str[index] = '+'; + } + + uint8_t attribute = 0; + if (loc) // 4-bit color index of MIDI channel + attribute |= (uint8_t)(loc->loc.MidCh & 0xF); + + attr[index] = (char)attribute; + ++index; + } + + str[index] = 0; + attr[index] = 0; +} /* TODO */ diff --git a/src/sound/opnmidi/opnmidi_opn2.cpp b/src/sound/opnmidi/opnmidi_opn2.cpp index 392294802..a5a60d226 100644 --- a/src/sound/opnmidi/opnmidi_opn2.cpp +++ b/src/sound/opnmidi/opnmidi_opn2.cpp @@ -48,23 +48,60 @@ #include "chips/gx_opn2.h" #endif +static const unsigned opn2_emulatorSupport = 0 +#ifndef OPNMIDI_DISABLE_NUKED_EMULATOR + | (1u << OPNMIDI_EMU_NUKED) +#endif +#ifndef OPNMIDI_DISABLE_MAME_EMULATOR + | (1u << OPNMIDI_EMU_MAME) +#endif +#ifndef OPNMIDI_DISABLE_GENS_EMULATOR + | (1u << OPNMIDI_EMU_GENS) +#endif +#ifndef OPNMIDI_DISABLE_GX_EMULATOR + | (1u << OPNMIDI_EMU_GX) +#endif +; -static const uint8_t NoteChannels[6] = { 0, 1, 2, 4, 5, 6 }; - -static inline void getOpnChannel(uint32_t in_channel, - unsigned &out_card, - uint8_t &out_port, - uint8_t &out_ch) +//! Check emulator availability +bool opn2_isEmulatorAvailable(int emulator) { - out_card = in_channel / 6; - uint8_t ch4 = in_channel % 6; - out_port = ((ch4 < 3) ? 0 : 1); - out_ch = ch4 % 3; + return (opn2_emulatorSupport & (1u << (unsigned)emulator)) != 0; } -void OPN2::cleanInstrumentBanks() +//! Find highest emulator +int opn2_getHighestEmulator() { - dynamic_banks.clear(); + int emu = -1; + for(unsigned m = opn2_emulatorSupport; m > 0; m >>= 1) + ++emu; + return emu; +} + +//! Find lowest emulator +int opn2_getLowestEmulator() +{ + int emu = -1; + unsigned m = opn2_emulatorSupport; + if(m > 0) + { + for(emu = 0; (m & 1) == 0; m >>= 1) + ++emu; + } + return emu; +} + +static const uint32_t g_noteChannelsMap[6] = { 0, 1, 2, 4, 5, 6 }; + +static inline void getOpnChannel(size_t in_channel, + size_t &out_chip, + uint8_t &out_port, + uint32_t &out_ch) +{ + out_chip = in_channel / 6; + size_t ch4 = in_channel % 6; + out_port = ((ch4 < 3) ? 0 : 1); + out_ch = static_cast(ch4 % 3); } static opnInstMeta2 makeEmptyInstrument() @@ -75,71 +112,128 @@ static opnInstMeta2 makeEmptyInstrument() return ins; } -const opnInstMeta2 OPN2::emptyInstrument = makeEmptyInstrument(); +const opnInstMeta2 OPN2::m_emptyInstrument = makeEmptyInstrument(); OPN2::OPN2() : - regLFO(0), - NumCards(1), + m_regLFOSetup(0), + m_numChips(1), + m_scaleModulators(false), + m_runAtPcmRate(false), + m_softPanning(false), m_musicMode(MODE_MIDI), - m_volumeScale(VOLUME_Generic) + m_volumeScale(VOLUME_Generic), + m_lfoEnable(false), + m_lfoFrequency(0) { + m_insBankSetup.volumeModel = OPN2::VOLUME_Generic; + m_insBankSetup.lfoEnable = false; + m_insBankSetup.lfoFrequency = 0; + // Initialize blank instruments banks - cleanInstrumentBanks(); + m_insBanks.clear(); } OPN2::~OPN2() { - ClearChips(); + clearChips(); } -void OPN2::PokeO(size_t card, uint8_t port, uint8_t index, uint8_t value) +bool OPN2::setupLocked() { - cardsOP2[card]->writeReg(port, index, value); + return (m_musicMode == MODE_CMF || + m_musicMode == MODE_IMF || + m_musicMode == MODE_RSXX); } -void OPN2::NoteOff(size_t c) +void OPN2::writeReg(size_t chip, uint8_t port, uint8_t index, uint8_t value) { - unsigned card; - uint8_t port, cc; - uint8_t ch4 = c % 6; - getOpnChannel(uint16_t(c), card, port, cc); - PokeO(card, 0, 0x28, NoteChannels[ch4]); + m_chips[chip]->writeReg(port, index, value); } -void OPN2::NoteOn(unsigned c, double hertz) // Hertz range: 0..131071 +void OPN2::writeRegI(size_t chip, uint8_t port, uint32_t index, uint32_t value) { - unsigned card; - uint8_t port, cc; - uint8_t ch4 = c % 6; - getOpnChannel(uint16_t(c), card, port, cc); + m_chips[chip]->writeReg(port, static_cast(index), static_cast(value)); +} - uint16_t x2 = 0x0000; +void OPN2::writePan(size_t chip, uint32_t index, uint32_t value) +{ + m_chips[chip]->writePan(static_cast(index), static_cast(value)); +} - if(hertz < 0 || hertz > 262143) // Avoid infinite loop +void OPN2::noteOff(size_t c) +{ + size_t chip; + uint8_t port; + uint32_t cc; + size_t ch4 = c % 6; + getOpnChannel(c, chip, port, cc); + writeRegI(chip, 0, 0x28, g_noteChannelsMap[ch4]); +} + +void OPN2::noteOn(size_t c, double hertz) // Hertz range: 0..131071 +{ + size_t chip; + uint8_t port; + uint32_t cc; + size_t ch4 = c % 6; + getOpnChannel(c, chip, port, cc); + + if(hertz < 0) // Avoid infinite loop return; - while((hertz >= 1023.75) && (x2 < 0x3800)) + uint32_t octave = 0, ftone = 0, mul_offset = 0; + const opnInstData &adli = m_insCache[c]; + + //Basic range until max of octaves reaching + while((hertz >= 1023.75) && (octave < 0x3800)) { hertz /= 2.0; // Calculate octave - x2 += 0x800; + octave += 0x800; + } + //Extended range, rely on frequency multiplication increment + while(hertz >= 2036.75) + { + hertz /= 2.0; // Calculate octave + mul_offset++; + } + ftone = octave + static_cast(hertz + 0.5); + + for(size_t op = 0; op < 4; op++) + { + uint32_t reg = adli.OPS[op].data[0]; + uint16_t address = static_cast(0x30 + (op * 4) + cc); + if(mul_offset > 0) // Increase frequency multiplication value + { + uint32_t dt = reg & 0xF0; + uint32_t mul = reg & 0x0F; + if((mul + mul_offset) > 0x0F) + { + mul_offset = 0; + mul = 0x0F; + } + writeRegI(chip, port, address, uint8_t(dt | (mul + mul_offset))); + } + else + { + writeRegI(chip, port, address, uint8_t(reg)); + } } - x2 += static_cast(hertz + 0.5); - PokeO(card, port, 0xA4 + cc, (x2>>8) & 0xFF);//Set frequency and octave - PokeO(card, port, 0xA0 + cc, x2 & 0xFF); - PokeO(card, 0, 0x28, 0xF0 + NoteChannels[ch4]); - pit[c] = static_cast(x2 >> 8); + writeRegI(chip, port, 0xA4 + cc, (ftone>>8) & 0xFF);//Set frequency and octave + writeRegI(chip, port, 0xA0 + cc, ftone & 0xFF); + writeRegI(chip, 0, 0x28, 0xF0 + g_noteChannelsMap[ch4]); } -void OPN2::Touch_Real(unsigned c, unsigned volume, uint8_t brightness) +void OPN2::touchNote(size_t c, uint8_t volume, uint8_t brightness) { if(volume > 127) volume = 127; - unsigned card; - uint8_t port, cc; - getOpnChannel(c, card, port, cc); + size_t chip; + uint8_t port; + uint32_t cc; + getOpnChannel(c, chip, port, cc); - const opnInstData &adli = ins[c]; + const opnInstData &adli = m_insCache[c]; uint8_t op_vol[4] = { @@ -170,16 +264,16 @@ void OPN2::Touch_Real(unsigned c, unsigned volume, uint8_t brightness) uint8_t alg = adli.fbalg & 0x07; for(uint8_t op = 0; op < 4; op++) { - bool do_op = alg_do[alg][op] || ScaleModulators; - uint8_t x = op_vol[op]; - uint8_t vol_res = do_op ? uint8_t(127 - (volume * (127 - (x&127)))/127) : x; + bool do_op = alg_do[alg][op] || m_scaleModulators; + uint32_t x = op_vol[op]; + uint32_t vol_res = do_op ? (127 - (static_cast(volume) * (127 - (x & 127)))/127) : x; if(brightness != 127) { - brightness = static_cast(::round(127.0 * ::sqrt((static_cast(brightness)) * (1.0 / 127.0)))); + brightness = static_cast(::round(127.0 * ::sqrt((static_cast(brightness)) * (1.0 / 127.0)))); if(!do_op) - vol_res = uint8_t(127 - (brightness * (127 - (uint32_t(vol_res) & 127))) / 127); + vol_res = (127 - (brightness * (127 - (static_cast(vol_res) & 127))) / 127); } - PokeO(card, port, 0x40 + cc + (4 * op), vol_res); + writeRegI(chip, port, 0x40 + cc + (4 * op), vol_res); } // Correct formula (ST3, AdPlug): // 63-((63-(instrvol))/63)*chanvol @@ -189,57 +283,68 @@ void OPN2::Touch_Real(unsigned c, unsigned volume, uint8_t brightness) // 63 + chanvol * (instrvol / 63.0 - 1) } -void OPN2::Patch(uint16_t c, const opnInstData &adli) +void OPN2::setPatch(size_t c, const opnInstData &instrument) { - unsigned card; - uint8_t port, cc; - getOpnChannel(uint16_t(c), card, port, cc); - ins[c] = adli; - #if 1 //Reg1-Op1, Reg1-Op2, Reg1-Op3, Reg1-Op4,.... + size_t chip; + uint8_t port; + uint32_t cc; + getOpnChannel(c, chip, port, cc); + m_insCache[c] = instrument; for(uint8_t d = 0; d < 7; d++) { for(uint8_t op = 0; op < 4; op++) - PokeO(card, port, 0x30 + (0x10 * d) + (op * 4) + cc, adli.OPS[op].data[d]); + writeRegI(chip, port, 0x30 + (0x10 * d) + (op * 4) + cc, instrument.OPS[op].data[d]); } - #else //Reg1-Op1, Reg2-Op1, Reg3-Op1, Reg4-Op1,.... - for(uint8_t op = 0; op < 4; op++) - { - PokeO(card, port, 0x30 + (op * 4) + cc, adli.OPS[op].data[0]); - PokeO(card, port, 0x40 + (op * 4) + cc, adli.OPS[op].data[1]); - PokeO(card, port, 0x50 + (op * 4) + cc, adli.OPS[op].data[2]); - PokeO(card, port, 0x60 + (op * 4) + cc, adli.OPS[op].data[3]); - PokeO(card, port, 0x70 + (op * 4) + cc, adli.OPS[op].data[4]); - PokeO(card, port, 0x80 + (op * 4) + cc, adli.OPS[op].data[5]); - PokeO(card, port, 0x90 + (op * 4) + cc, adli.OPS[op].data[6]); - } - #endif - PokeO(card, port, 0xB0 + cc, adli.fbalg);//Feedback/Algorithm - regBD[c] = (regBD[c] & 0xC0) | (adli.lfosens & 0x3F); - PokeO(card, port, 0xB4 + cc, regBD[c]);//Panorame and LFO bits + writeRegI(chip, port, 0xB0 + cc, instrument.fbalg);//Feedback/Algorithm + m_regLFOSens[c] = (m_regLFOSens[c] & 0xC0) | (instrument.lfosens & 0x3F); + writeRegI(chip, port, 0xB4 + cc, m_regLFOSens[c]);//Panorame and LFO bits } -void OPN2::Pan(unsigned c, unsigned value) +void OPN2::setPan(size_t c, uint8_t value) { - unsigned card; - uint8_t port, cc; - getOpnChannel(uint16_t(c), card, port, cc); - const opnInstData &adli = ins[c]; - uint8_t val = (value & 0xC0) | (adli.lfosens & 0x3F); - regBD[c] = val; - PokeO(card, port, 0xB4 + cc, val); + size_t chip; + uint8_t port; + uint32_t cc; + getOpnChannel(c, chip, port, cc); + const opnInstData &adli = m_insCache[c]; + uint8_t val = 0; + if(m_softPanning) + { + val = (OPN_PANNING_BOTH & 0xC0) | (adli.lfosens & 0x3F); + writePan(chip, c % 6, value); + writeRegI(chip, port, 0xB4 + cc, val); + } + else + { + int panning = 0; + if(value < 64 + 32) panning |= OPN_PANNING_LEFT; + if(value >= 64 - 32) panning |= OPN_PANNING_RIGHT; + val = (panning & 0xC0) | (adli.lfosens & 0x3F); + writePan(chip, c % 6, 64); + writeRegI(chip, port, 0xB4 + cc, val); + } + m_regLFOSens[c] = val; } -void OPN2::Silence() // Silence all OPL channels. +void OPN2::silenceAll() // Silence all OPL channels. { - for(unsigned c = 0; c < NumChannels; ++c) + for(size_t c = 0; c < m_numChannels; ++c) { - NoteOff(c); - Touch_Real(c, 0); + noteOff(c); + touchNote(c, 0); } } -void OPN2::ChangeVolumeRangesModel(OPNMIDI_VolumeModels volumeModel) +void OPN2::commitLFOSetup() +{ + uint8_t regLFOSetup = (m_lfoEnable ? 8 : 0) | (m_lfoFrequency & 7); + m_regLFOSetup = regLFOSetup; + for(size_t chip = 0; chip < m_numChips; ++chip) + writeReg(chip, 0, 0x22, regLFOSetup); +} + +void OPN2::setVolumeScaleModel(OPNMIDI_VolumeModels volumeModel) { switch(volumeModel) { @@ -250,8 +355,8 @@ void OPN2::ChangeVolumeRangesModel(OPNMIDI_VolumeModels volumeModel) m_volumeScale = OPN2::VOLUME_Generic; break; - case OPNMIDI_VolumeModel_CMF: - m_volumeScale = OPN2::VOLUME_CMF; + case OPNMIDI_VolumeModel_NativeOPN2: + m_volumeScale = OPN2::VOLUME_NATIVE; break; case OPNMIDI_VolumeModel_DMX: @@ -268,70 +373,101 @@ void OPN2::ChangeVolumeRangesModel(OPNMIDI_VolumeModels volumeModel) } } -void OPN2::ClearChips() +OPNMIDI_VolumeModels OPN2::getVolumeScaleModel() { - for(size_t i = 0; i < cardsOP2.size(); i++) - cardsOP2[i].reset(NULL); - cardsOP2.clear(); + switch(m_volumeScale) + { + default: + case OPN2::VOLUME_Generic: + return OPNMIDI_VolumeModel_Generic; + case OPN2::VOLUME_NATIVE: + return OPNMIDI_VolumeModel_NativeOPN2; + case OPN2::VOLUME_DMX: + return OPNMIDI_VolumeModel_DMX; + case OPN2::VOLUME_APOGEE: + return OPNMIDI_VolumeModel_APOGEE; + case OPN2::VOLUME_9X: + return OPNMIDI_VolumeModel_9X; + } } -void OPN2::Reset(int emulator, unsigned long PCM_RATE) +void OPN2::clearChips() { - ClearChips(); - ins.clear(); - pit.clear(); - regBD.clear(); - cardsOP2.resize(NumCards, AdlMIDI_SPtr()); + for(size_t i = 0; i < m_chips.size(); i++) + m_chips[i].reset(NULL); + m_chips.clear(); +} - for(size_t i = 0; i < cardsOP2.size(); i++) +void OPN2::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) +{ +#if !defined(ADLMIDI_AUDIO_TICK_HANDLER) + ADL_UNUSED(audioTickHandler); +#endif + clearChips(); + m_insCache.clear(); + m_regLFOSens.clear(); + m_chips.resize(m_numChips, AdlMIDI_SPtr()); + + for(size_t i = 0; i < m_chips.size(); i++) { + OPNChipBase *chip; + switch(emulator) { default: + assert(false); + abort(); #ifndef OPNMIDI_DISABLE_MAME_EMULATOR case OPNMIDI_EMU_MAME: - cardsOP2[i].reset(new MameOPN2()); + chip = new MameOPN2; break; #endif #ifndef OPNMIDI_DISABLE_NUKED_EMULATOR case OPNMIDI_EMU_NUKED: - cardsOP2[i].reset(new NukedOPN2()); + chip = new NukedOPN2; break; #endif #ifndef OPNMIDI_DISABLE_GENS_EMULATOR case OPNMIDI_EMU_GENS: - cardsOP2[i].reset(new GensOPN2()); + chip = new GensOPN2; break; #endif #ifndef OPNMIDI_DISABLE_GX_EMULATOR case OPNMIDI_EMU_GX: - cardsOP2[i].reset(new GXOPN2()); + chip = new GXOPN2; break; #endif } - cardsOP2[i]->setRate((uint32_t)PCM_RATE, 7670454); - if(runAtPcmRate) - cardsOP2[i]->setRunningAtPcmRate(true); + m_chips[i].reset(chip); + chip->setChipId((uint32_t)i); + chip->setRate((uint32_t)PCM_RATE, 7670454); + if(m_runAtPcmRate) + chip->setRunningAtPcmRate(true); +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) + chip->setAudioTickHandlerInstance(audioTickHandler); +#endif } - NumChannels = NumCards * 6; - ins.resize(NumChannels, emptyInstrument.opn[0]); - pit.resize(NumChannels, 0); - regBD.resize(NumChannels, 0); + m_numChannels = m_numChips * 6; + m_insCache.resize(m_numChannels, m_emptyInstrument.opn[0]); + m_regLFOSens.resize(m_numChannels, 0); - for(unsigned card = 0; card < NumCards; ++card) + uint8_t regLFOSetup = (m_lfoEnable ? 8 : 0) | (m_lfoFrequency & 7); + m_regLFOSetup = regLFOSetup; + + for(size_t card = 0; card < m_numChips; ++card) { - PokeO(card, 0, 0x22, regLFO);//push current LFO state - PokeO(card, 0, 0x27, 0x00); //set Channel 3 normal mode - PokeO(card, 0, 0x2B, 0x00); //Disable DAC + writeReg(card, 0, 0x22, regLFOSetup);//push current LFO state + writeReg(card, 0, 0x27, 0x00); //set Channel 3 normal mode + writeReg(card, 0, 0x2B, 0x00); //Disable DAC //Shut up all channels - PokeO(card, 0, 0x28, 0x00 ); //Note Off 0 channel - PokeO(card, 0, 0x28, 0x01 ); //Note Off 1 channel - PokeO(card, 0, 0x28, 0x02 ); //Note Off 2 channel - PokeO(card, 0, 0x28, 0x04 ); //Note Off 3 channel - PokeO(card, 0, 0x28, 0x05 ); //Note Off 4 channel - PokeO(card, 0, 0x28, 0x06 ); //Note Off 5 channel + writeReg(card, 0, 0x28, 0x00 ); //Note Off 0 channel + writeReg(card, 0, 0x28, 0x01 ); //Note Off 1 channel + writeReg(card, 0, 0x28, 0x02 ); //Note Off 2 channel + writeReg(card, 0, 0x28, 0x04 ); //Note Off 3 channel + writeReg(card, 0, 0x28, 0x05 ); //Note Off 4 channel + writeReg(card, 0, 0x28, 0x06 ); //Note Off 5 channel } - Silence(); + silenceAll(); } diff --git a/src/sound/opnmidi/opnmidi_private.cpp b/src/sound/opnmidi/opnmidi_private.cpp index 1faced79d..47c2c87ac 100644 --- a/src/sound/opnmidi/opnmidi_private.cpp +++ b/src/sound/opnmidi/opnmidi_private.cpp @@ -25,31 +25,12 @@ std::string OPN2MIDI_ErrorString; -int opn2RefreshNumCards(OPN2_MIDIPlayer * /*device*/) -{ -// OPNMIDIplay *play = reinterpret_cast(device->opn2_midiPlayer); - //OPN uses 4-op instruments only -// unsigned n_fourop[2] = {0, 0}, n_total[2] = {0, 0}; -// for(unsigned a = 0; a < 256; ++a) -// { -// unsigned insno = banks[device->OpnBank][a]; -// if(insno == 198) continue; -// ++n_total[a / 128]; -// if(adlins[insno].adlno1 != adlins[insno].adlno2) -// ++n_fourop[a / 128]; -// } +// Generator callback on audio rate ticks -// device->NumFourOps = -// (n_fourop[0] >= n_total[0] * 7 / 8) ? device->NumCards * 6 -// : (n_fourop[0] < n_total[0] * 1 / 8) ? 0 -// : (device->NumCards == 1 ? 1 : device->NumCards * 4); -// reinterpret_cast(device->opn2_midiPlayer)->opn.NumFourOps = device->NumFourOps; -// if(n_fourop[0] >= n_total[0] * 15 / 16 && device->NumFourOps == 0) -// { -// OPN2MIDI_ErrorString = "ERROR: You have selected a bank that consists almost exclusively of four-op patches.\n" -// " The results (silence + much cpu load) would be probably\n" -// " not what you want, therefore ignoring the request.\n"; -// return -1; -// } - return 0; +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) +void opn2_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate) +{ + reinterpret_cast(instance)->AudioTick(chipId, rate); } +#endif + diff --git a/src/sound/opnmidi/opnmidi_private.hpp b/src/sound/opnmidi/opnmidi_private.hpp index ed10dcd10..353cc3d03 100644 --- a/src/sound/opnmidi/opnmidi_private.hpp +++ b/src/sound/opnmidi/opnmidi_private.hpp @@ -24,11 +24,13 @@ #ifndef ADLMIDI_PRIVATE_HPP #define ADLMIDI_PRIVATE_HPP +#define OPNMIDI_UNSTABLE_API + // Setup compiler defines useful for exporting required public API symbols in gme.cpp #ifndef OPNMIDI_EXPORT -# if defined (_WIN32) && defined(ADLMIDI_BUILD_DLL) +# if defined (_WIN32) && defined(OPNMIDI_BUILD_DLL) # define OPNMIDI_EXPORT __declspec(dllexport) -# elif defined (LIBADLMIDI_VISIBILITY) +# elif defined (LIBOPNMIDI_VISIBILITY) && defined (__GNUC__) # define OPNMIDI_EXPORT __attribute__((visibility ("default"))) # else # define OPNMIDI_EXPORT @@ -36,28 +38,35 @@ #endif #ifdef _WIN32 -# undef NO_OLDNAMES +#define NOMINMAX 1 +#endif +#ifdef _WIN32 +# undef NO_OLDNAMES +# include # ifdef _MSC_VER # ifdef _WIN64 typedef __int64 ssize_t; # else typedef __int32 ssize_t; # endif -# define NOMINMAX //Don't override std::min and std::max +# define NOMINMAX 1 //Don't override std::min and std::max +# else +# ifdef _WIN64 +typedef int64_t ssize_t; +# else +typedef int32_t ssize_t; +# endif # endif # include #endif -#ifdef USE_LEGACY_EMULATOR // Kept for a backward compatibility -#define OPNMIDI_USE_LEGACY_EMULATOR -#endif - #include #include #include #include #include +#include // nothrow #include #include #include @@ -67,6 +76,7 @@ typedef __int32 ssize_t; #include // vector #include // deque #include // exp, log, ceil +#include #include #include #include // numeric_limit @@ -100,11 +110,22 @@ typedef __int32 ssize_t; #define INT32_MAX 0x7fffffff #endif -#include "fraction.hpp" +#include "file_reader.hpp" + +#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER +// Rename class to avoid ABI collisions +#define BW_MidiSequencer OpnMidiSequencer +#include "midi_sequencer.hpp" +typedef BW_MidiSequencer MidiSequencer; +#endif//OPNMIDI_DISABLE_MIDI_SEQUENCER + #include "chips/opn_chip_base.h" #include "opnbank.h" -#include "opnmidi.h" + +#define OPNMIDI_BUILD +#include "opnmidi.h" //Main API + #include "opnmidi_ptr.hpp" #include "opnmidi_bankmap.h" @@ -114,6 +135,9 @@ typedef __int32 ssize_t; #define OPN_PANNING_RIGHT 0x40 #define OPN_PANNING_BOTH 0xC0 +#define OPN_MAX_CHIPS 100 +#define OPN_MAX_CHIPS_STR "100" + extern std::string OPN2MIDI_ErrorString; /* @@ -122,7 +146,7 @@ extern std::string OPN2MIDI_ErrorString; template inline Real opn2_cvtReal(int32_t x) { - return x * ((Real)1 / INT16_MAX); + return static_cast(x) * (static_cast(1) / static_cast(INT16_MAX)); } inline int32_t opn2_cvtS16(int32_t x) { @@ -162,80 +186,212 @@ inline int32_t opn2_cvtU32(int32_t x) } class OPNMIDIplay; +/** + * @brief OPN2 Chip management class + */ class OPN2 { -public: friend class OPNMIDIplay; - uint32_t NumChannels; - char ____padding[4]; - std::vector > cardsOP2; -private: - std::vector ins; // patch data, cached, needed by Touch() - std::vector pit; // value poked to B0, cached, needed by NoteOff)( - std::vector regBD; - uint8_t regLFO; - - void cleanInstrumentBanks(); public: + enum { PercussionTag = 1 << 15 }; + + //! Total number of chip channels between all running emulators + uint32_t m_numChannels; + //! Just a padding. Reserved. + char _padding[4]; + //! Running chip emulators + std::vector > m_chips; +private: + //! Cached patch data, needed by Touch() + std::vector m_insCache; + //! Cached per-channel LFO sensitivity flags + std::vector m_regLFOSens; + //! LFO setup registry cache + uint8_t m_regLFOSetup; + +public: + /** + * @brief MIDI bank entry + */ struct Bank { + //! MIDI Bank instruments opnInstMeta2 ins[128]; }; typedef BasicBankMap BankMap; - BankMap dynamic_banks; + //! MIDI bank instruments data + BankMap m_insBanks; + //! MIDI bank-wide setup + OpnBankSetup m_insBankSetup; + public: - static const opnInstMeta2 emptyInstrument; - enum { PercussionTag = 1 << 15 }; + //! Blank instrument template + static const opnInstMeta2 m_emptyInstrument; //! Total number of running concurrent emulated chips - unsigned int NumCards; + uint32_t m_numChips; //! Carriers-only are scaled by default by volume level. This flag will tell to scale modulators too. - bool ScaleModulators; + bool m_scaleModulators; //! Run emulator at PCM rate if that possible. Reduces sounding accuracy, but decreases CPU usage on lower rates. - bool runAtPcmRate; + bool m_runAtPcmRate; + //! Enable soft panning + bool m_softPanning; - char ___padding2[3]; + //! Just a padding. Reserved. + char _padding2[3]; + /** + * @brief Music playing mode + */ enum MusicMode { + //! MIDI mode MODE_MIDI, - //MODE_IMF, OPN2 chip is not able to interpret OPL's except of a creepy and ugly conversion :-P - //MODE_CMF, CMF also is not supported :-P + //! Id-Software Music mode + MODE_IMF, + //! Creative Music Files mode + MODE_CMF, + //! EA-MUS (a.k.a. RSXX) mode MODE_RSXX } m_musicMode; + /** + * @brief Volume models enum + */ enum VolumesScale { + //! Generic volume model (linearization of logarithmic scale) VOLUME_Generic, - VOLUME_CMF, + //! OPN2 native logarithmic scale + VOLUME_NATIVE, + //! DMX volume scale logarithmic table VOLUME_DMX, + //! Apoge Sound System volume scaling model VOLUME_APOGEE, + //! Windows 9x driver volume scale table VOLUME_9X } m_volumeScale; + //! Reserved + bool m_lfoEnable; + uint8_t m_lfoFrequency; + + //! Category of the channel + /*! 1 = DAC, 0 = regular + */ + std::vector m_channelCategory; + + + /** + * @brief C.O. Constructor + */ OPN2(); + + /** + * @brief C.O. Destructor + */ ~OPN2(); - char ____padding3[8]; - std::vector four_op_category; // 1 = quad-master, 2 = quad-slave, 0 = regular - // 3 = percussion BassDrum - // 4 = percussion Snare - // 5 = percussion Tom - // 6 = percussion Crash cymbal - // 7 = percussion Hihat - // 8 = percussion slave - void PokeO(size_t card, uint8_t port, uint8_t index, uint8_t value); + /** + * @brief Checks are setup locked to be changed on the fly or not + * @return true when setup on the fly is locked + */ + bool setupLocked(); - void NoteOff(size_t c); - void NoteOn(unsigned c, double hertz); - void Touch_Real(unsigned c, unsigned volume, uint8_t brightness = 127); + /** + * @brief Write data to OPN2 chip register + * @param chip Index of emulated chip. In hardware OPN2 builds, this parameter is ignored + * @param port Port of the chip to write + * @param index Register address to write + * @param value Value to write + */ + void writeReg(size_t chip, uint8_t port, uint8_t index, uint8_t value); - void Patch(uint16_t c, const opnInstData &adli); - void Pan(unsigned c, unsigned value); - void Silence(); - void ChangeVolumeRangesModel(OPNMIDI_VolumeModels volumeModel); - void ClearChips(); - void Reset(int emulator, unsigned long PCM_RATE); + /** + * @brief Write data to OPN2 chip register + * @param chip Index of emulated chip. In hardware OPN2 builds, this parameter is ignored + * @param port Port of the chip to write + * @param index Register address to write + * @param value Value to write + */ + void writeRegI(size_t chip, uint8_t port, uint32_t index, uint32_t value); + + /** + * @brief Write to soft panning control of OPN2 chip emulator + * @param chip Index of emulated chip. + * @param address Register of channel to write + * @param value Value to write + */ + void writePan(size_t chip, uint32_t index, uint32_t value); + + /** + * @brief Off the note in specified chip channel + * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + */ + void noteOff(size_t c); + + /** + * @brief On the note in specified chip channel with specified frequency of the tone + * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param hertz Frequency of the tone in hertzes + */ + void noteOn(size_t c, double hertz); + + /** + * @brief Change setup of instrument in specified chip channel + * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param volume Volume level (from 0 to 127) + * @param brightness CC74 Brightness level (from 0 to 127) + */ + void touchNote(size_t c, uint8_t volume, uint8_t brightness = 127); + + /** + * @brief Set the instrument into specified chip channel + * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param instrument Instrument data to set into the chip channel + */ + void setPatch(size_t c, const opnInstData &instrument); + + /** + * @brief Set panpot position + * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param value 3-bit panpot value + */ + void setPan(size_t c, uint8_t value); + + /** + * @brief Shut up all chip channels + */ + void silenceAll(); + + /** + * @brief commit LFO enable and frequency + */ + void commitLFOSetup(); + + /** + * @brief Set the volume scaling model + * @param volumeModel Type of volume scale model scale + */ + void setVolumeScaleModel(OPNMIDI_VolumeModels volumeModel); + + /** + * @brief Get the volume scaling model + */ + OPNMIDI_VolumeModels getVolumeScaleModel(); + + /** + * @brief Clean up all running emulated chip instances + */ + void clearChips(); + + /** + * @brief Reset chip properties and initialize them + * @param emulator Type of chip emulator + * @param PCM_RATE Output sample rate to generate on output + * @param audioTickHandler PCM-accurate clock hook + */ + void reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler); }; @@ -245,17 +401,11 @@ public: struct MIDIEventHooks { MIDIEventHooks() : - onEvent(NULL), - onEvent_userData(NULL), onNote(NULL), onNote_userData(NULL), onDebugMessage(NULL), onDebugMessage_userData(NULL) {} - //! Raw MIDI event hook - typedef void (*RawEventHook)(void *userdata, uint8_t type, uint8_t subtype, uint8_t channel, const uint8_t *data, size_t len); - RawEventHook onEvent; - void *onEvent_userData; //! Note on/off hooks typedef void (*NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend); @@ -273,208 +423,121 @@ class OPNMIDIplay { friend void opn2_reset(struct OPN2_MIDIPlayer*); public: - OPNMIDIplay(unsigned long sampleRate = 22050); + explicit OPNMIDIplay(unsigned long sampleRate = 22050); ~OPNMIDIplay() {} void applySetup(); + void partialReset(); + void resetMIDI(); + /**********************Internal structures and classes**********************/ /** - * @brief A little class gives able to read filedata from disk and also from a memory segment + * @brief Persistent settings for each MIDI channel */ - class fileReader - { - public: - enum relTo - { - SET = 0, - CUR = 1, - END = 2 - }; - - fileReader() - { - fp = NULL; - mp = NULL; - mp_size = 0; - mp_tell = 0; - } - ~fileReader() - { - close(); - } - - void openFile(const char *path) - { - #ifndef _WIN32 - fp = std::fopen(path, "rb"); - #else - wchar_t widePath[MAX_PATH]; - int size = MultiByteToWideChar(CP_UTF8, 0, path, (int)std::strlen(path), widePath, MAX_PATH); - widePath[size] = '\0'; - fp = _wfopen(widePath, L"rb"); - #endif - _fileName = path; - mp = NULL; - mp_size = 0; - mp_tell = 0; - } - - void openData(const void *mem, size_t lenght) - { - fp = NULL; - mp = mem; - mp_size = lenght; - mp_tell = 0; - } - - void seek(long pos, int rel_to) - { - if(fp) - std::fseek(fp, pos, rel_to); - else - { - switch(rel_to) - { - case SET: - mp_tell = static_cast(pos); - break; - - case END: - mp_tell = mp_size - static_cast(pos); - break; - - case CUR: - mp_tell = mp_tell + static_cast(pos); - break; - } - - if(mp_tell > mp_size) - mp_tell = mp_size; - } - } - - inline void seeku(uint64_t pos, int rel_to) - { - seek(static_cast(pos), rel_to); - } - - size_t read(void *buf, size_t num, size_t size) - { - if(fp) - return std::fread(buf, num, size, fp); - else - { - size_t pos = 0; - size_t maxSize = static_cast(size * num); - - while((pos < maxSize) && (mp_tell < mp_size)) - { - reinterpret_cast(buf)[pos] = reinterpret_cast(mp)[mp_tell]; - mp_tell++; - pos++; - } - - return pos; - } - } - - int getc() - { - if(fp) - return std::getc(fp); - else - { - if(mp_tell >= mp_size) return -1; - int x = reinterpret_cast(mp)[mp_tell]; - mp_tell++; - return x; - } - } - - size_t tell() - { - if(fp) - return static_cast(std::ftell(fp)); - else - return mp_tell; - } - - void close() - { - if(fp) std::fclose(fp); - - fp = NULL; - mp = NULL; - mp_size = 0; - mp_tell = 0; - } - - bool isValid() - { - return (fp) || (mp); - } - - bool eof() - { - if(fp) - return (std::feof(fp) != 0); - else - return mp_tell >= mp_size; - } - std::string _fileName; - std::FILE *fp; - const void *mp; - size_t mp_size; - size_t mp_tell; - }; - - // Persistent settings for each MIDI channel struct MIDIchannel { - uint16_t portamento; - uint8_t bank_lsb, bank_msb; + //! LSB Bank number + uint8_t bank_lsb, + //! MSB Bank number + bank_msb; + //! Current patch number uint8_t patch; - uint8_t volume, expression; - uint8_t panning, vibrato, aftertouch, sustain; + //! Volume level + uint8_t volume, + //! Expression level + expression; + //! Panning level + uint8_t panning, + //! Vibrato level + vibrato, + //! Channel aftertouch level + aftertouch; + //! Portamento time + uint16_t portamento; + //! Is Pedal sustain active + bool sustain; + //! Is Soft pedal active + bool softPedal; + //! Is portamento enabled + bool portamentoEnable; + //! Source note number used by portamento + int8_t portamentoSource; // note number or -1 + //! Portamento rate + double portamentoRate; //! Per note Aftertouch values uint8_t noteAftertouch[128]; //! Is note aftertouch has any non-zero value bool noteAfterTouchInUse; - char ____padding[6]; + //! Reserved + char _padding[6]; + //! Pitch bend value int bend; + //! Pitch bend sensitivity double bendsense; - int bendsense_lsb, bendsense_msb; - double vibpos, vibspeed, vibdepth; - int64_t vibdelay; - uint8_t lastlrpn, lastmrpn; + //! Pitch bend sensitivity LSB value + int bendsense_lsb, + //! Pitch bend sensitivity MSB value + bendsense_msb; + //! Vibrato position value + double vibpos, + //! Vibrato speed value + vibspeed, + //! Vibrato depth value + vibdepth; + //! Vibrato delay time + int64_t vibdelay_us; + //! Last LSB part of RPN value received + uint8_t lastlrpn, + //! Last MSB poart of RPN value received + lastmrpn; + //! Interpret RPN value as NRPN bool nrpn; + //! Brightness level uint8_t brightness; + + //! Is melodic channel turned into percussion bool is_xg_percussion; + + /** + * @brief Per-Note information + */ struct NoteInfo { + //! Note number uint8_t note; + //! Is note active bool active; - // Current pressure + //! Current pressure uint8_t vol; - // Note vibrato (a part of Note Aftertouch feature) + //! Note vibrato (a part of Note Aftertouch feature) uint8_t vibrato; - char ____padding[1]; - // Tone selected on noteon: - int16_t tone; - char ____padding2[10]; - // Patch selected on noteon; index to banks[AdlBank][] + //! Tone selected on noteon: + int16_t noteTone; + //! Current tone (!= noteTone if gliding note) + double currentTone; + //! Gliding rate + double glideRate; + //! Patch selected on noteon; index to bank.ins[] size_t midiins; - // Patch selected + //! Is note the percussion instrument + bool isPercussion; + //! Note that plays missing instrument. Doesn't using any chip channels + bool isBlank; + //! Patch selected const opnInstMeta2 *ains; enum { MaxNumPhysChans = 2, MaxNumPhysItemCount = MaxNumPhysChans, }; + + /** + * @brief Reference to currently using chip channel + */ struct Phys { //! Destination chip channel @@ -495,11 +558,12 @@ public: return !operator==(oth); } }; - // List of OPN2 channels it is currently occupying. + + //! List of OPN2 channels it is currently occupying. Phys chip_channels[MaxNumPhysItemCount]; //! Count of used channels. unsigned chip_channels_count; - // + Phys *phys_find(unsigned chip_chan) { Phys *ph = NULL; @@ -508,18 +572,18 @@ public: ph = &chip_channels[i]; return ph; } - Phys *phys_find_or_create(unsigned chip_chan) + Phys *phys_find_or_create(uint16_t chip_chan) { Phys *ph = phys_find(chip_chan); if(!ph) { if(chip_channels_count < MaxNumPhysItemCount) { ph = &chip_channels[chip_channels_count++]; - ph->chip_chan = (uint16_t)chip_chan; + ph->chip_chan = chip_chan; } } return ph; } - Phys *phys_ensure_find_or_create(unsigned chip_chan) + Phys *phys_ensure_find_or_create(uint16_t chip_chan) { Phys *ph = phys_find_or_create(chip_chan); assert(ph); @@ -540,7 +604,13 @@ public: phys_erase_at(ph); } }; - char ____padding2[5]; + + //! Reserved + char _padding2[5]; + //! Count of gliding notes in this channel + unsigned gliding_note_count; + + //! Active notes in the channel NoteInfo activenotes[128]; struct activenoteiterator @@ -624,6 +694,9 @@ public: } } + /** + * @brief Reset channel into initial state + */ void reset() { resetAllControllers(); @@ -636,6 +709,10 @@ public: nrpn = false; is_xg_percussion = false; } + + /** + * @brief Reset all MIDI controllers into initial state + */ void resetAllControllers() { bend = 0; @@ -644,35 +721,52 @@ public: updateBendSensitivity(); volume = 100; expression = 127; - sustain = 0; + sustain = false; + softPedal = false; vibrato = 0; aftertouch = 0; std::memset(noteAftertouch, 0, 128); noteAfterTouchInUse = false; vibspeed = 2 * 3.141592653 * 5.0; vibdepth = 0.5 / 127; - vibdelay = 0; - panning = OPN_PANNING_BOTH; + vibdelay_us = 0; + panning = 64; portamento = 0; + portamentoEnable = false; + portamentoSource = -1; + portamentoRate = HUGE_VAL; brightness = 127; } + + /** + * @brief Has channel vibrato to process + * @return + */ bool hasVibrato() { return (vibrato > 0) || (aftertouch > 0) || noteAfterTouchInUse; } + + /** + * @brief Commit pitch bend sensitivity value from MSB and LSB + */ void updateBendSensitivity() { int cent = bendsense_msb * 128 + bendsense_lsb; bendsense = cent * (1.0 / (128 * 8192)); } + MIDIchannel() { activenotes_clear(); + gliding_note_count = 0; reset(); } }; - // Additional information about OPN channels + /** + * @brief Additional information about OPN2 channels + */ struct OpnChannel { struct Location @@ -683,24 +777,33 @@ public: { return MidCh == l.MidCh && note == l.note; } bool operator!=(const Location &l) const { return !operator==(l); } - char ____padding[1]; + char _padding[1]; }; struct LocationData { LocationData *prev, *next; Location loc; - bool sustained; - char ____padding[3]; + enum { + Sustain_None = 0x00, + Sustain_Pedal = 0x01, + Sustain_Sostenuto = 0x02, + Sustain_ANY = Sustain_Pedal | Sustain_Sostenuto, + }; + uint32_t sustained; + char _padding[3]; MIDIchannel::NoteInfo::Phys ins; // a copy of that in phys[] //! Has fixed sustain, don't iterate "on" timeout bool fixed_sustain; //! Timeout until note will be allowed to be killed by channel manager while it is on - int64_t kon_time_until_neglible; - int64_t vibdelay; + int64_t kon_time_until_neglible_us; + int64_t vibdelay_us; }; - // If the channel is keyoff'd - int64_t koff_time_until_neglible; + //! Time left until sounding will be muted after key off + int64_t koff_time_until_neglible_us; + + //! Recently passed instrument, improves a goodness of released but busy channel when matching + MIDIchannel::NoteInfo::Phys recent_ins; enum { users_max = 128 }; LocationData *users_first, *users_free_cells; @@ -717,12 +820,13 @@ public: void users_assign(const LocationData *users, size_t count); // For channel allocation: - OpnChannel(): koff_time_until_neglible(0) + OpnChannel(): koff_time_until_neglible_us(0) { users_clear(); + std::memset(&recent_ins, 0, sizeof(MIDIchannel::NoteInfo::Phys)); } - OpnChannel(const OpnChannel &oth): koff_time_until_neglible(oth.koff_time_until_neglible) + OpnChannel(const OpnChannel &oth): koff_time_until_neglible_us(oth.koff_time_until_neglible_us) { if(oth.users_first) { @@ -735,139 +839,33 @@ public: OpnChannel &operator=(const OpnChannel &oth) { - koff_time_until_neglible = oth.koff_time_until_neglible; + koff_time_until_neglible_us = oth.koff_time_until_neglible_us; users_assign(oth.users_first, oth.users_size); return *this; } - void AddAge(int64_t ms); + /** + * @brief Increases age of active note in microseconds time + * @param us Amount time in microseconds + */ + void addAge(int64_t us); }; #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER /** - * @brief MIDI Event utility container + * @brief MIDI files player sequencer */ - class MidiEvent - { - public: - MidiEvent(); - - enum Types - { - T_UNKNOWN = 0x00, - T_NOTEOFF = 0x08,//size == 2 - T_NOTEON = 0x09,//size == 2 - T_NOTETOUCH = 0x0A,//size == 2 - T_CTRLCHANGE = 0x0B,//size == 2 - T_PATCHCHANGE = 0x0C,//size == 1 - T_CHANAFTTOUCH = 0x0D,//size == 1 - T_WHEEL = 0x0E,//size == 2 - - T_SYSEX = 0xF0,//size == len - T_SYSCOMSPOSPTR = 0xF2,//size == 2 - T_SYSCOMSNGSEL = 0xF3,//size == 1 - T_SYSEX2 = 0xF7,//size == len - T_SPECIAL = 0xFF - }; - enum SubTypes - { - ST_SEQNUMBER = 0x00,//size == 2 - ST_TEXT = 0x01,//size == len - ST_COPYRIGHT = 0x02,//size == len - ST_SQTRKTITLE = 0x03,//size == len - ST_INSTRTITLE = 0x04,//size == len - ST_LYRICS = 0x05,//size == len - ST_MARKER = 0x06,//size == len - ST_CUEPOINT = 0x07,//size == len - ST_DEVICESWITCH = 0x09,//size == len - ST_MIDICHPREFIX = 0x20,//size == 1 - - ST_ENDTRACK = 0x2F,//size == 0 - ST_TEMPOCHANGE = 0x51,//size == 3 - ST_SMPTEOFFSET = 0x54,//size == 5 - ST_TIMESIGNATURE = 0x55, //size == 4 - ST_KEYSIGNATURE = 0x59,//size == 2 - ST_SEQUENCERSPEC = 0x7F, //size == len - - /* Non-standard, internal ADLMIDI usage only */ - ST_LOOPSTART = 0xE1,//size == 0 - ST_LOOPEND = 0xE2,//size == 0 - ST_RAWOPL = 0xE3//size == 0 - }; - //! Main type of event - uint8_t type; - //! Sub-type of the event - uint8_t subtype; - //! Targeted MIDI channel - uint8_t channel; - //! Is valid event - uint8_t isValid; - //! Reserved 5 bytes padding - uint8_t __padding[4]; - //! Absolute tick position (Used for the tempo calculation only) - uint64_t absPosition; - //! Raw data of this event - std::vector data; - }; + MidiSequencer m_sequencer; /** - * @brief A track position event contains a chain of MIDI events until next delay value - * - * Created with purpose to sort events by type in the same position - * (for example, to keep controllers always first than note on events or lower than note-off events) + * @brief Interface between MIDI sequencer and this library */ - class MidiTrackRow - { - public: - MidiTrackRow(); - void reset(); - //! Absolute time position in seconds - double time; - //! Delay to next event in ticks - uint64_t delay; - //! Absolute position in ticks - uint64_t absPos; - //! Delay to next event in seconds - double timeDelay; - std::vector events; - /** - * @brief Sort events in this position - */ - void sortEvents(bool *noteStates = NULL); - }; + BW_MidiRtInterface m_sequencerInterface; /** - * @brief Tempo change point entry. Used in the MIDI data building function only. + * @brief Initialize MIDI sequencer interface */ - struct TempoChangePoint - { - uint64_t absPos; - fraction tempo; - }; - //P.S. I declared it here instead of local in-function because C++99 can't process templates with locally-declared structures - - typedef std::list MidiTrackQueue; - - // Information about each track - struct PositionNew - { - bool began; - char padding[7]; - double wait; - double absTimePosition; - struct TrackInfo - { - size_t ptr; - uint64_t delay; - int status; - char padding2[4]; - MidiTrackQueue::iterator pos; - TrackInfo(): ptr(0), delay(0), status(0) {} - }; - std::vector track; - PositionNew(): began(false), wait(0.0), absTimePosition(0.0), track() - {} - }; + void initSequencerInterface(); #endif //OPNMIDI_DISABLE_MIDI_SEQUENCER struct Setup @@ -875,11 +873,12 @@ public: int emulator; bool runAtPcmRate; unsigned int OpnBank; - unsigned int NumCards; + unsigned int numChips; unsigned int LogarithmicVolumes; int VolumeModel; + int lfoEnable; + int lfoFrequency; //unsigned int SkipForward; - bool loopingIsEnabled; int ScaleModulators; bool fullRangeBrightnessCC74; @@ -898,127 +897,134 @@ public: unsigned long PCM_RATE; }; + /** + * @brief MIDI Marker entry + */ struct MIDI_MarkerEntry { + //! Label of marker std::string label; + //! Absolute position in seconds double pos_time; + //! Absolute position in ticks in the track uint64_t pos_ticks; }; - std::vector Ch; - //bool cmf_percussion_mode; + //! Available MIDI Channels + std::vector m_midiChannels; + //! Master volume, controlled via SysEx + uint8_t m_masterVolume; + + //! SysEx device ID + uint8_t m_sysExDeviceId; + + /** + * @brief MIDI Synthesizer mode + */ + enum SynthMode + { + Mode_GM = 0x00, + Mode_GS = 0x01, + Mode_XG = 0x02, + Mode_GM2 = 0x04, + }; + //! MIDI Synthesizer mode + uint32_t m_synthMode; + + //! Installed function hooks MIDIEventHooks hooks; private: - std::map devices; - std::map current_device; + //! Per-track MIDI devices map + std::map m_midiDevices; + //! Current MIDI device per track + std::map m_currentMidiDevice; - std::vector ch; + //! Chip channels map + std::vector m_chipChannels; //! Counter of arpeggio processing size_t m_arpeggioCounter; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - std::vector > TrackData; - - PositionNew CurrentPositionNew, LoopBeginPositionNew, trackBeginPositionNew; - - //! Full song length in seconds - double fullSongTimeLength; - //! Delay after song playd before rejecting the output stream requests - double postSongWaitDelay; - - //! Loop start time - double loopStartTime; - //! Loop end time - double loopEndTime; +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) + //! Audio tick counter + uint32_t m_audioTickCounter; #endif - //! Local error string - std::string errorString; + //! Local error string std::string errorStringOut; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - //! Pre-processed track data storage - std::vector trackDataNew; -#endif - //! Missing instruments catches - std::set caugh_missing_instruments; + std::set caugh_missing_instruments; //! Missing melodic banks catches - std::set caugh_missing_banks_melodic; + std::set caugh_missing_banks_melodic; //! Missing percussion banks catches - std::set caugh_missing_banks_percussion; - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - /** - * @brief Build MIDI track data from the raw track data storage - * @return true if everything successfully processed, or false on any error - */ - bool buildTrackData(); - - /** - * @brief Parse one event from raw MIDI track stream - * @param [_inout] ptr pointer to pointer to current position on the raw data track - * @param [_in] end address to end of raw track data, needed to validate position and size - * @param [_inout] status status of the track processing - * @return Parsed MIDI event entry - */ - MidiEvent parseEvent(uint8_t **ptr, uint8_t *end, int &status); -#endif + std::set caugh_missing_banks_percussion; public: const std::string &getErrorString(); void setErrorString(const std::string &err); -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - std::string musTitle; - std::string musCopyright; - std::vector musTrackTitles; - std::vector musMarkers; + //! OPN2 Chip manager + OPN2 m_synth; - fraction InvDeltaTicks, Tempo; - //! Tempo multiplier - double tempoMultiplier; - bool atEnd, - loopStart, - loopEnd, - invalidLoop; /*Loop points are invalid (loopStart after loopEnd or loopStart and loopEnd are on same place)*/ - char ____padding2[2]; -#endif - OPN2 opn; - - int32_t outBuf[1024]; + //! Generator output buffer + int32_t m_outBuf[1024]; + //! Synthesizer setup Setup m_setup; - static uint64_t ReadBEint(const void *buffer, size_t nbytes); - static uint64_t ReadLEint(const void *buffer, size_t nbytes); - /** - * @brief Standard MIDI Variable-Length numeric value parser without of validation - * @param [_inout] ptr Pointer to memory block that contains begin of variable-length value - * @return Unsigned integer that conains parsed variable-length value + * @brief Load bank from file + * @param filename Path to bank file + * @return true on succes */ - uint64_t ReadVarLen(uint8_t **ptr); - /** - * @brief Secure Standard MIDI Variable-Length numeric value parser with anti-out-of-range protection - * @param [_inout] ptr Pointer to memory block that contains begin of variable-length value, will be iterated forward - * @param [_in end Pointer to end of memory block where variable-length value is stored (after end of track) - * @param [_out] ok Reference to boolean which takes result of variable-length value parsing - * @return Unsigned integer that conains parsed variable-length value - */ - uint64_t ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok); - bool LoadBank(const std::string &filename); + + /** + * @brief Load bank from memory block + * @param data Pointer to memory block where raw bank file is stored + * @param size Size of given memory block + * @return true on succes + */ bool LoadBank(const void *data, size_t size); - bool LoadBank(fileReader &fr); + + /** + * @brief Load bank from opened FileAndMemReader class + * @param fr Instance with opened file + * @return true on succes + */ + bool LoadBank(FileAndMemReader &fr); #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER + /** + * @brief MIDI file loading pre-process + * @return true on success, false on failure + */ + bool LoadMIDI_pre(); + + /** + * @brief MIDI file loading post-process + * @return true on success, false on failure + */ + bool LoadMIDI_post(); + + /** + * @brief Load music file from a file + * @param filename Path to music file + * @return true on success, false on failure + */ + bool LoadMIDI(const std::string &filename); + + /** + * @brief Load music file from the memory block + * @param data pointer to the memory block + * @param size size of memory block + * @return true on success, false on failure + */ bool LoadMIDI(const void *data, size_t size); - bool LoadMIDI(fileReader &fr); /** * @brief Periodic tick handler. @@ -1027,80 +1033,205 @@ public: * @return desired number of seconds until next call */ double Tick(double s, double granularity); -#endif +#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER /** * @brief Process extra iterators like vibrato or arpeggio * @param s seconds since last call */ - void TickIteratos(double s); + void TickIterators(double s); -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - /** - * @brief Change current position to specified time position in seconds - * @param seconds Absolute time position in seconds - */ - void seek(double seconds); - - /** - * @brief Gives current time position in seconds - * @return Current time position in seconds - */ - double tell(); - - /** - * @brief Gives time length of current song in seconds - * @return Time length of current song in seconds - */ - double timeLength(); - - /** - * @brief Gives loop start time position in seconds - * @return Loop start time position in seconds or -1 if song has no loop points - */ - double getLoopStart(); - - /** - * @brief Gives loop end time position in seconds - * @return Loop end time position in seconds or -1 if song has no loop points - */ - double getLoopEnd(); - - /** - * @brief Return to begin of current song - */ - void rewind(); - - /** - * @brief Set tempo multiplier - * @param tempo Tempo multiplier: 1.0 - original tempo. >1 - faster, <1 - slower - */ - void setTempo(double tempo); -#endif /* RealTime event triggers */ + /** + * @brief Reset state of all channels + */ void realTime_ResetState(); + /** + * @brief Note On event + * @param channel MIDI channel + * @param note Note key (from 0 to 127) + * @param velocity Velocity level (from 0 to 127) + * @return true if Note On event was accepted + */ bool realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity); + + /** + * @brief Note Off event + * @param channel MIDI channel + * @param note Note key (from 0 to 127) + */ void realTime_NoteOff(uint8_t channel, uint8_t note); + /** + * @brief Note aftertouch event + * @param channel MIDI channel + * @param note Note key (from 0 to 127) + * @param atVal After-Touch level (from 0 to 127) + */ void realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal); + + /** + * @brief Channel aftertouch event + * @param channel MIDI channel + * @param atVal After-Touch level (from 0 to 127) + */ void realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal); + /** + * @brief Controller Change event + * @param channel MIDI channel + * @param type Type of controller + * @param value Value of the controller (from 0 to 127) + */ void realTime_Controller(uint8_t channel, uint8_t type, uint8_t value); + /** + * @brief Patch change + * @param channel MIDI channel + * @param patch Patch Number (from 0 to 127) + */ void realTime_PatchChange(uint8_t channel, uint8_t patch); + /** + * @brief Pitch bend change + * @param channel MIDI channel + * @param pitch Concoctated raw pitch value + */ void realTime_PitchBend(uint8_t channel, uint16_t pitch); + + /** + * @brief Pitch bend change + * @param channel MIDI channel + * @param msb MSB of pitch value + * @param lsb LSB of pitch value + */ void realTime_PitchBend(uint8_t channel, uint8_t msb, uint8_t lsb); + /** + * @brief LSB Bank Change CC + * @param channel MIDI channel + * @param lsb LSB value of bank number + */ void realTime_BankChangeLSB(uint8_t channel, uint8_t lsb); + + /** + * @brief MSB Bank Change CC + * @param channel MIDI channel + * @param lsb MSB value of bank number + */ void realTime_BankChangeMSB(uint8_t channel, uint8_t msb); + + /** + * @brief Bank Change (united value) + * @param channel MIDI channel + * @param bank Bank number value + */ void realTime_BankChange(uint8_t channel, uint16_t bank); + /** + * @brief Sets the Device identifier + * @param id 7-bit Device identifier + */ + void setDeviceId(uint8_t id); + + /** + * @brief System Exclusive message + * @param msg Raw SysEx Message + * @param size Length of SysEx message + * @return true if message was passed successfully. False on any errors + */ + bool realTime_SysEx(const uint8_t *msg, size_t size); + + /** + * @brief Turn off all notes and mute the sound of releasing notes + */ void realTime_panic(); + /** + * @brief Device switch (to extend 16-channels limit of MIDI standard) + * @param track MIDI track index + * @param data Device name + * @param length Length of device name string + */ + void realTime_deviceSwitch(size_t track, const char *data, size_t length); + + /** + * @brief Currently selected device index + * @param track MIDI track index + * @return Multiple 16 value + */ + size_t realTime_currentDevice(size_t track); + +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) + // Audio rate tick handler + void AudioTick(uint32_t chipId, uint32_t rate); +#endif + private: + /** + * @brief Hardware manufacturer (Used for SysEx) + */ + enum + { + Manufacturer_Roland = 0x41, + Manufacturer_Yamaha = 0x43, + Manufacturer_UniversalNonRealtime = 0x7E, + Manufacturer_UniversalRealtime = 0x7F + }; + + /** + * @brief Roland Mode (Used for SysEx) + */ + enum + { + RolandMode_Request = 0x11, + RolandMode_Send = 0x12 + }; + + /** + * @brief Device model (Used for SysEx) + */ + enum + { + RolandModel_GS = 0x42, + RolandModel_SC55 = 0x45, + YamahaModel_XG = 0x4C + }; + + /** + * @brief Process generic SysEx events + * @param dev Device ID + * @param realtime Is real-time event + * @param data Raw SysEx data + * @param size Size of given SysEx data + * @return true when event was successfully handled + */ + bool doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size); + + /** + * @brief Process events specific to Roland devices + * @param dev Device ID + * @param data Raw SysEx data + * @param size Size of given SysEx data + * @return true when event was successfully handled + */ + bool doRolandSysEx(unsigned dev, const uint8_t *data, size_t size); + + /** + * @brief Process events specific to Yamaha devices + * @param dev Device ID + * @param data Raw SysEx data + * @param size Size of given SysEx data + * @return true when event was successfully handled + */ + bool doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size); + +private: + /** + * @brief Note Update properties + */ enum { Upd_Patch = 0x1, @@ -1113,42 +1244,144 @@ private: Upd_OffMute = Upd_Off + Upd_Mute }; - void NoteUpdate(uint16_t MidCh, + /** + * @brief Update active note + * @param MidCh MIDI Channel where note is processing + * @param i Iterator that points to active note in the MIDI channel + * @param props_mask Properties to update + * @param select_adlchn Specify chip channel, or -1 - all chip channels used by the note + */ + void noteUpdate(size_t midCh, MIDIchannel::activenoteiterator i, unsigned props_mask, int32_t select_adlchn = -1); -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - bool ProcessEventsNew(bool isSeek = false); - void HandleEvent(size_t tk, const MidiEvent &evt, int &status); -#endif + void noteUpdateAll(size_t midCh, unsigned props_mask); - // Determine how good a candidate this adlchannel - // would be for playing a note from this instrument. - int64_t CalculateAdlChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins, uint16_t /*MidCh*/) const; + /** + * @brief Determine how good a candidate this adlchannel would be for playing a note from this instrument. + * @param c Wanted chip channel + * @param ins Instrument wanted to be used in this channel + * @return Calculated coodness points + */ + int64_t calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const; - // A new note will be played on this channel using this instrument. - // Kill existing notes on this channel (or don't, if we do arpeggio) - void PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins); + /** + * @brief A new note will be played on this channel using this instrument. + * @param c Wanted chip channel + * @param ins Instrument wanted to be used in this channel + * Kill existing notes on this channel (or don't, if we do arpeggio) + */ + void prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins); - void KillOrEvacuate( + /** + * @brief Kills note that uses wanted channel. When arpeggio is possible, note is evaluating to another channel + * @param from_channel Wanted chip channel + * @param j Chip channel instance + * @param i MIDI Channel active note instance + */ + void killOrEvacuate( size_t from_channel, OpnChannel::LocationData *j, MIDIchannel::activenoteiterator i); - void Panic(); - void KillSustainingNotes(int32_t MidCh = -1, int32_t this_adlchn = -1); - void SetRPN(unsigned MidCh, unsigned value, bool MSB); - //void UpdatePortamento(unsigned MidCh) - void NoteUpdate_All(uint16_t MidCh, unsigned props_mask); - void NoteOff(uint16_t MidCh, uint8_t note); - void UpdateVibrato(double amount); - void UpdateArpeggio(double /*amount*/); + + /** + * @brief Off all notes and silence sound + */ + void panic(); + + /** + * @brief Kill note, sustaining by pedal or sostenuto + * @param MidCh MIDI channel, -1 - all MIDI channels + * @param this_adlchn Chip channel, -1 - all chip channels + * @param sustain_type Type of systain to process + */ + void killSustainingNotes(int32_t midCh = -1, + int32_t this_adlchn = -1, + uint32_t sustain_type = OpnChannel::LocationData::Sustain_ANY); + /** + * @brief Find active notes and mark them as sostenuto-sustained + * @param MidCh MIDI channel, -1 - all MIDI channels + */ + void markSostenutoNotes(int32_t midCh = -1); + + /** + * @brief Set RPN event value + * @param MidCh MIDI channel + * @param value 1 byte part of RPN value + * @param MSB is MSB or LSB part of value + */ + void setRPN(size_t midCh, unsigned value, bool MSB); + + /** + * @brief Update portamento setup in MIDI channel + * @param midCh MIDI channel where portamento needed to be updated + */ + void updatePortamento(size_t midCh); + + /** + * @brief Off the note + * @param midCh MIDI channel + * @param note Note to off + */ + void noteOff(size_t midCh, uint8_t note); + + /** + * @brief Update processing of vibrato to amount of seconds + * @param amount Amount value in seconds + */ + void updateVibrato(double amount); + + /** + * @brief Update auto-arpeggio + * @param amount Amount value in seconds [UNUSED] + */ + void updateArpeggio(double /*amount*/); + + /** + * @brief Update Portamento gliding to amount of seconds + * @param amount Amount value in seconds + */ + void updateGlide(double amount); public: - uint64_t ChooseDevice(const std::string &name); + /** + * @brief Checks was device name used or not + * @param name Name of MIDI device + * @return Offset of the MIDI Channels, multiple to 16 + */ + size_t chooseDevice(const std::string &name); + + /** + * @brief Gets a textual description of the state of chip channels + * @param text character pointer for text + * @param attr character pointer for text attributes + * @param size number of characters available to write + */ + void describeChannels(char *text, char *attr, size_t size); }; -extern int opn2RefreshNumCards(OPN2_MIDIPlayer *device); +#if defined(ADLMIDI_AUDIO_TICK_HANDLER) +extern void opn2_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate); +#endif +/** + * @brief Check emulator availability + * @param emulator Emulator ID (Opn2_Emulator) + * @return true when emulator is available + */ +extern bool opn2_isEmulatorAvailable(int emulator); + +/** + * @brief Find highest emulator + * @return The Opn2_Emulator enum value which contains ID of highest emulator + */ +extern int opn2_getHighestEmulator(); + +/** + * @brief Find lowest emulator + * @return The Opn2_Emulator enum value which contains ID of lowest emulator + */ +extern int opn2_getLowestEmulator(); #endif // ADLMIDI_PRIVATE_HPP diff --git a/src/sound/opnmidi/wopn/wopn_file.c b/src/sound/opnmidi/wopn/wopn_file.c new file mode 100644 index 000000000..f2bea78e9 --- /dev/null +++ b/src/sound/opnmidi/wopn/wopn_file.c @@ -0,0 +1,622 @@ +/* + * Wohlstand's OPN2 Bank File - a bank format to store OPN2 timbre data and setup + * + * Copyright (c) 2018 Vitaly Novichkov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "wopn_file.h" +#include +#include + +static const char *wopn2_magic1 = "WOPN2-BANK\0"; +static const char *wopn2_magic2 = "WOPN2-B2NK\0"; +static const char *opni_magic1 = "WOPN2-INST\0"; +static const char *opni_magic2 = "WOPN2-IN2T\0"; + +static const uint16_t wopn_latest_version = 2; + +enum +{ + WOPN_INST_SIZE_V1 = 65, + WOPN_INST_SIZE_V2 = 69 +}; + +static uint16_t toUint16LE(const uint8_t *arr) +{ + uint16_t num = arr[0]; + num |= ((arr[1] << 8) & 0xFF00); + return num; +} + +static uint16_t toUint16BE(const uint8_t *arr) +{ + uint16_t num = arr[1]; + num |= ((arr[0] << 8) & 0xFF00); + return num; +} + +static int16_t toSint16BE(const uint8_t *arr) +{ + int16_t num = *(const int8_t *)(&arr[0]); + num *= 1 << 8; + num |= arr[1]; + return num; +} + +static void fromUint16LE(uint16_t in, uint8_t *arr) +{ + arr[0] = in & 0x00FF; + arr[1] = (in >> 8) & 0x00FF; +} + +static void fromUint16BE(uint16_t in, uint8_t *arr) +{ + arr[1] = in & 0x00FF; + arr[0] = (in >> 8) & 0x00FF; +} + +static void fromSint16BE(int16_t in, uint8_t *arr) +{ + arr[1] = in & 0x00FF; + arr[0] = ((uint16_t)in >> 8) & 0x00FF; +} + + +WOPNFile *WOPN_Init(uint16_t melodic_banks, uint16_t percussive_banks) +{ + WOPNFile *file = NULL; + if(melodic_banks == 0) + return NULL; + if(percussive_banks == 0) + return NULL; + file = (WOPNFile*)calloc(1, sizeof(WOPNFile)); + if(!file) + return NULL; + file->banks_count_melodic = melodic_banks; + file->banks_count_percussion = percussive_banks; + file->banks_melodic = (WOPNBank*)calloc(1, sizeof(WOPNBank) * melodic_banks ); + file->banks_percussive = (WOPNBank*)calloc(1, sizeof(WOPNBank) * percussive_banks ); + return file; +} + +void WOPN_Free(WOPNFile *file) +{ + if(file) + { + if(file->banks_melodic) + free(file->banks_melodic); + if(file->banks_percussive) + free(file->banks_percussive); + free(file); + } +} + +int WOPN_BanksCmp(const WOPNFile *bank1, const WOPNFile *bank2) +{ + int res = 1; + + res &= (bank1->version == bank2->version); + res &= (bank1->lfo_freq == bank2->lfo_freq); + res &= (bank1->volume_model == bank2->volume_model); + res &= (bank1->banks_count_melodic == bank2->banks_count_melodic); + res &= (bank1->banks_count_percussion == bank2->banks_count_percussion); + + if(res) + { + int i; + for(i = 0; i < bank1->banks_count_melodic; i++) + res &= (memcmp(&bank1->banks_melodic[i], &bank2->banks_melodic[i], sizeof(WOPNBank)) == 0); + if(res) + { + for(i = 0; i < bank1->banks_count_percussion; i++) + res &= (memcmp(&bank1->banks_percussive[i], &bank2->banks_percussive[i], sizeof(WOPNBank)) == 0); + } + } + + return res; +} + +static void WOPN_parseInstrument(WOPNInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays) +{ + int l; + strncpy(ins->inst_name, (const char*)cursor, 32); + ins->inst_name[32] = '\0'; + ins->note_offset = toSint16BE(cursor + 32); + ins->midi_velocity_offset = 0; /* TODO: for future version > 2 */ + ins->percussion_key_number = cursor[34]; + ins->inst_flags = 0; /* TODO: for future version > 2 */ + ins->fbalg = cursor[35]; + ins->lfosens = cursor[36]; + for(l = 0; l < 4; l++) + { + size_t off = 37 + (size_t)(l) * 7; + ins->operators[l].dtfm_30 = cursor[off + 0]; + ins->operators[l].level_40 = cursor[off + 1]; + ins->operators[l].rsatk_50 = cursor[off + 2]; + ins->operators[l].amdecay1_60 = cursor[off + 3]; + ins->operators[l].decay2_70 = cursor[off + 4]; + ins->operators[l].susrel_80 = cursor[off + 5]; + ins->operators[l].ssgeg_90 = cursor[off + 6]; + } + if((version >= 2) && has_sounding_delays) + { + ins->delay_on_ms = toUint16BE(cursor + 65); + ins->delay_off_ms = toUint16BE(cursor + 67); + + /* Null delays indicate the blank instrument in version 2 */ + if((version < 3) && ins->delay_on_ms == 0 && ins->delay_off_ms == 0) + ins->inst_flags |= WOPN_Ins_IsBlank; + } +} + +static void WOPN_writeInstrument(WOPNInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays) +{ + int l; + strncpy((char*)cursor, ins->inst_name, 32); + fromSint16BE(ins->note_offset, cursor + 32); + cursor[34] = ins->percussion_key_number; + cursor[35] = ins->fbalg; + cursor[36] = ins->lfosens; + for(l = 0; l < 4; l++) + { + size_t off = 37 + (size_t)(l) * 7; + cursor[off + 0] = ins->operators[l].dtfm_30; + cursor[off + 1] = ins->operators[l].level_40; + cursor[off + 2] = ins->operators[l].rsatk_50; + cursor[off + 3] = ins->operators[l].amdecay1_60; + cursor[off + 4] = ins->operators[l].decay2_70; + cursor[off + 5] = ins->operators[l].susrel_80; + cursor[off + 6] = ins->operators[l].ssgeg_90; + } + if((version >= 2) && has_sounding_delays) + { + if((version < 3) && (ins->inst_flags & WOPN_Ins_IsBlank) != 0) + { + /* Null delays indicate the blank instrument in version 2 */ + fromUint16BE(0, cursor + 65); + fromUint16BE(0, cursor + 67); + } + else + { + fromUint16BE(ins->delay_on_ms, cursor + 65); + fromUint16BE(ins->delay_off_ms, cursor + 67); + } + } +} + +WOPNFile *WOPN_LoadBankFromMem(void *mem, size_t length, int *error) +{ + WOPNFile *outFile = NULL; + uint16_t i = 0, j = 0, k = 0; + uint16_t version = 0; + uint16_t count_melodic_banks = 1; + uint16_t count_percussive_banks = 1; + uint8_t *cursor = (uint8_t *)mem; + + WOPNBank *bankslots[2]; + uint16_t bankslots_sizes[2]; + +#define SET_ERROR(err) \ +{\ + WOPN_Free(outFile);\ + if(error)\ + {\ + *error = err;\ + }\ +} + +#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } + + if(!cursor) + { + SET_ERROR(WOPN_ERR_NULL_POINTER); + return NULL; + } + + {/* Magic number */ + if(length < 11) + { + SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); + return NULL; + } + if(memcmp(cursor, wopn2_magic1, 11) == 0) + { + version = 1; + } + else if(memcmp(cursor, wopn2_magic2, 11) != 0) + { + SET_ERROR(WOPN_ERR_BAD_MAGIC); + return NULL; + } + GO_FORWARD(11); + } + + if (version == 0) + {/* Version code */ + if(length < 2) + { + SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); + return NULL; + } + version = toUint16LE(cursor); + if(version > wopn_latest_version) + { + SET_ERROR(WOPN_ERR_NEWER_VERSION); + return NULL; + } + GO_FORWARD(2); + } + + {/* Header of WOPN */ + uint8_t head[5]; + if(length < 5) + { + SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); + return NULL; + } + memcpy(head, cursor, 5); + count_melodic_banks = toUint16BE(head); + count_percussive_banks = toUint16BE(head + 2); + GO_FORWARD(5); + + outFile = WOPN_Init(count_melodic_banks, count_percussive_banks); + if(!outFile) + { + SET_ERROR(WOPN_ERR_OUT_OF_MEMORY); + return NULL; + } + + outFile->version = version; + outFile->lfo_freq = head[4]; + outFile->volume_model = 0; + } + + bankslots_sizes[0] = count_melodic_banks; + bankslots[0] = outFile->banks_melodic; + bankslots_sizes[1] = count_percussive_banks; + bankslots[1] = outFile->banks_percussive; + + if(version >= 2) /* Bank names and LSB/MSB titles */ + { + for(i = 0; i < 2; i++) + { + for(j = 0; j < bankslots_sizes[i]; j++) + { + if(length < 34) + { + SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); + return NULL; + } + strncpy(bankslots[i][j].bank_name, (const char*)cursor, 32); + bankslots[i][j].bank_name[32] = '\0'; + bankslots[i][j].bank_midi_lsb = cursor[32]; + bankslots[i][j].bank_midi_msb = cursor[33]; + GO_FORWARD(34); + } + } + } + + {/* Read instruments data */ + uint16_t insSize = 0; + if(version > 1) + insSize = WOPN_INST_SIZE_V2; + else + insSize = WOPN_INST_SIZE_V1; + for(i = 0; i < 2; i++) + { + if(length < (insSize * 128) * (size_t)bankslots_sizes[i]) + { + SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); + return NULL; + } + + for(j = 0; j < bankslots_sizes[i]; j++) + { + for(k = 0; k < 128; k++) + { + WOPNInstrument *ins = &bankslots[i][j].ins[k]; + WOPN_parseInstrument(ins, cursor, version, 1); + GO_FORWARD(insSize); + } + } + } + } + +#undef GO_FORWARD +#undef SET_ERROR + + return outFile; +} + +int WOPN_LoadInstFromMem(OPNIFile *file, void *mem, size_t length) +{ + uint16_t version = 0; + uint8_t *cursor = (uint8_t *)mem; + uint16_t ins_size; + + if(!cursor) + return WOPN_ERR_NULL_POINTER; + +#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } + + {/* Magic number */ + if(length < 11) + return WOPN_ERR_UNEXPECTED_ENDING; + if(memcmp(cursor, opni_magic1, 11) == 0) + version = 1; + else if(memcmp(cursor, opni_magic2, 11) != 0) + return WOPN_ERR_BAD_MAGIC; + GO_FORWARD(11); + } + + if (version == 0) {/* Version code */ + if(length < 2) + return WOPN_ERR_UNEXPECTED_ENDING; + version = toUint16LE(cursor); + if(version > wopn_latest_version) + return WOPN_ERR_NEWER_VERSION; + GO_FORWARD(2); + } + + file->version = version; + + {/* is drum flag */ + if(length < 1) + return WOPN_ERR_UNEXPECTED_ENDING; + file->is_drum = *cursor; + GO_FORWARD(1); + } + + if(version > 1) + /* Skip sounding delays are not part of single-instrument file + * two sizes of uint16_t will be subtracted */ + ins_size = WOPN_INST_SIZE_V2 - (sizeof(uint16_t) * 2); + else + ins_size = WOPN_INST_SIZE_V1; + + if(length < ins_size) + return WOPN_ERR_UNEXPECTED_ENDING; + + WOPN_parseInstrument(&file->inst, cursor, version, 0); + GO_FORWARD(ins_size); + + return WOPN_ERR_OK; +#undef GO_FORWARD +} + +size_t WOPN_CalculateBankFileSize(WOPNFile *file, uint16_t version) +{ + size_t final_size = 0; + size_t ins_size = 0; + + if(version == 0) + version = wopn_latest_version; + + if(!file) + return 0; + final_size += 11 + 2 + 2 + 2 + 1; + /* + * Magic number, + * Version, + * Count of melodic banks, + * Count of percussive banks, + * Chip specific flags + */ + + if(version >= 2) + { + /* Melodic banks meta-data */ + final_size += (32 + 1 + 1) * file->banks_count_melodic; + /* Percussive banks meta-data */ + final_size += (32 + 1 + 1) * file->banks_count_percussion; + } + + if(version >= 2) + ins_size = WOPN_INST_SIZE_V2; + else + ins_size = WOPN_INST_SIZE_V1; + /* Melodic instruments */ + final_size += (ins_size * 128) * file->banks_count_melodic; + /* Percussive instruments */ + final_size += (ins_size * 128) * file->banks_count_percussion; + + return final_size; +} + +size_t WOPN_CalculateInstFileSize(OPNIFile *file, uint16_t version) +{ + size_t final_size = 0; + size_t ins_size = 0; + + if(version == 0) + version = wopn_latest_version; + + if(!file) + return 0; + final_size += 11 + 1; + /* + * Magic number, + * is percussive instrument + */ + + /* Version */ + if (version > 1) + final_size += 2; + + if(version > 1) + /* Skip sounding delays are not part of single-instrument file + * two sizes of uint16_t will be subtracted */ + ins_size = WOPN_INST_SIZE_V2 - (sizeof(uint16_t) * 2); + else + ins_size = WOPN_INST_SIZE_V1; + final_size += ins_size; + + return final_size; +} + +int WOPN_SaveBankToMem(WOPNFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm) +{ + uint8_t *cursor = (uint8_t *)dest_mem; + uint16_t ins_size = 0; + uint16_t i, j, k; + uint16_t banks_melodic = force_gm ? 1 : file->banks_count_melodic; + uint16_t banks_percussive = force_gm ? 1 : file->banks_count_percussion; + + WOPNBank *bankslots[2]; + uint16_t bankslots_sizes[2]; + + if(version == 0) + version = wopn_latest_version; + +#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } + + if(length < 11) + return WOPN_ERR_UNEXPECTED_ENDING; + if(version > 1) + memcpy(cursor, wopn2_magic2, 11); + else + memcpy(cursor, wopn2_magic1, 11); + GO_FORWARD(11); + + if(version > 1) + { + if(length < 2) + return WOPN_ERR_UNEXPECTED_ENDING; + fromUint16LE(version, cursor); + GO_FORWARD(2); + } + + if(length < 2) + return WOPN_ERR_UNEXPECTED_ENDING; + fromUint16BE(banks_melodic, cursor); + GO_FORWARD(2); + + if(length < 2) + return WOPN_ERR_UNEXPECTED_ENDING; + fromUint16BE(banks_percussive, cursor); + GO_FORWARD(2); + + if(length < 1) + return WOPN_ERR_UNEXPECTED_ENDING; + cursor[0] = file->lfo_freq; + GO_FORWARD(1); + + bankslots[0] = file->banks_melodic; + bankslots_sizes[0] = banks_melodic; + bankslots[1] = file->banks_percussive; + bankslots_sizes[1] = banks_percussive; + + if(version >= 2) + { + for(i = 0; i < 2; i++) + { + for(j = 0; j < bankslots_sizes[i]; j++) + { + if(length < 34) + return WOPN_ERR_UNEXPECTED_ENDING; + strncpy((char*)cursor, bankslots[i][j].bank_name, 32); + cursor[32] = bankslots[i][j].bank_midi_lsb; + cursor[33] = bankslots[i][j].bank_midi_msb; + GO_FORWARD(34); + } + } + } + + {/* Write instruments data */ + if(version >= 2) + ins_size = WOPN_INST_SIZE_V2; + else + ins_size = WOPN_INST_SIZE_V1; + for(i = 0; i < 2; i++) + { + if(length < (ins_size * 128) * (size_t)bankslots_sizes[i]) + return WOPN_ERR_UNEXPECTED_ENDING; + + for(j = 0; j < bankslots_sizes[i]; j++) + { + for(k = 0; k < 128; k++) + { + WOPNInstrument *ins = &bankslots[i][j].ins[k]; + WOPN_writeInstrument(ins, cursor, version, 1); + GO_FORWARD(ins_size); + } + } + } + } + + return WOPN_ERR_OK; +#undef GO_FORWARD +} + +int WOPN_SaveInstToMem(OPNIFile *file, void *dest_mem, size_t length, uint16_t version) +{ + uint8_t *cursor = (uint8_t *)dest_mem; + uint16_t ins_size; + + if(!cursor) + return WOPN_ERR_NULL_POINTER; + + if(version == 0) + version = wopn_latest_version; + +#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } + + {/* Magic number */ + if(length < 11) + return WOPN_ERR_UNEXPECTED_ENDING; + if(version > 1) + memcpy(cursor, opni_magic2, 11); + else + memcpy(cursor, opni_magic1, 11); + GO_FORWARD(11); + } + + if (version > 1) + {/* Version code */ + if(length < 2) + return WOPN_ERR_UNEXPECTED_ENDING; + fromUint16LE(version, cursor); + GO_FORWARD(2); + } + + {/* is drum flag */ + if(length < 1) + return WOPN_ERR_UNEXPECTED_ENDING; + *cursor = file->is_drum; + GO_FORWARD(1); + } + + if(version > 1) + /* Skip sounding delays are not part of single-instrument file + * two sizes of uint16_t will be subtracted */ + ins_size = WOPN_INST_SIZE_V2 - (sizeof(uint16_t) * 2); + else + ins_size = WOPN_INST_SIZE_V1; + + if(length < ins_size) + return WOPN_ERR_UNEXPECTED_ENDING; + + WOPN_writeInstrument(&file->inst, cursor, version, 0); + GO_FORWARD(ins_size); + + return WOPN_ERR_OK; +#undef GO_FORWARD +} diff --git a/src/sound/opnmidi/wopn/wopn_file.h b/src/sound/opnmidi/wopn/wopn_file.h new file mode 100644 index 000000000..cd0d6b4d4 --- /dev/null +++ b/src/sound/opnmidi/wopn/wopn_file.h @@ -0,0 +1,250 @@ +/* + * Wohlstand's OPN2 Bank File - a bank format to store OPN2 timbre data and setup + * + * Copyright (c) 2018 Vitaly Novichkov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef WOPN_FILE_H +#define WOPN_FILE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(__STDC_VERSION__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L)) \ + || defined(__STRICT_ANSI__) || !defined(__cplusplus) +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int int16_t; +typedef unsigned short int uint16_t; +#endif + +/* Volume scaling model implemented in the libOPNMIDI */ +typedef enum WOPN_VolumeModel +{ + WOPN_VM_Generic = 0 +} WOPN_VolumeModel; + +typedef enum WOPN_InstrumentFlags +{ + /* Is pseudo eight-operator (two 4-operator voices) instrument */ + WOPN_Ins_Pseudo8op = 0x01, + /* Is a blank instrument entry */ + WOPN_Ins_IsBlank = 0x02, + + /* Mask of the flags range */ + WOPN_Ins_ALL_MASK = 0x03 +} WOPN_InstrumentFlags; + +/* Error codes */ +typedef enum WOPN_ErrorCodes +{ + WOPN_ERR_OK = 0, + /* Magic number is not maching */ + WOPN_ERR_BAD_MAGIC, + /* Too short file */ + WOPN_ERR_UNEXPECTED_ENDING, + /* Zero banks count */ + WOPN_ERR_INVALID_BANKS_COUNT, + /* Version of file is newer than supported by current version of library */ + WOPN_ERR_NEWER_VERSION, + /* Out of memory */ + WOPN_ERR_OUT_OF_MEMORY, + /* Given null pointer memory data */ + WOPN_ERR_NULL_POINTER +} WOPN_ErrorCodes; + +/* OPN2 Oerators data */ +typedef struct WOPNOperator +{ + /* Detune and frequency multiplication register data */ + uint8_t dtfm_30; + /* Total level register data */ + uint8_t level_40; + /* Rate scale and attack register data */ + uint8_t rsatk_50; + /* Amplitude modulation enable and Decay-1 register data */ + uint8_t amdecay1_60; + /* Decay-2 register data */ + uint8_t decay2_70; + /* Sustain and Release register data */ + uint8_t susrel_80; + /* SSG-EG register data */ + uint8_t ssgeg_90; +} WOPNOperator; + +/* Instrument entry */ +typedef struct WOPNInstrument +{ + /* Title of the instrument */ + char inst_name[34]; + /* MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */ + int16_t note_offset; + /* Reserved */ + int8_t midi_velocity_offset; + /* Percussion MIDI base tone number at which this drum will be played */ + uint8_t percussion_key_number; + /* Enum WOPN_InstrumentFlags */ + uint8_t inst_flags; + /* Feedback and Algorithm register data */ + uint8_t fbalg; + /* LFO Sensitivity register data */ + uint8_t lfosens; + /* Operators register data */ + WOPNOperator operators[4]; + /* Millisecond delay of sounding while key is on */ + uint16_t delay_on_ms; + /* Millisecond delay of sounding after key off */ + uint16_t delay_off_ms; +} WOPNInstrument; + +/* Bank entry */ +typedef struct WOPNBank +{ + /* Name of bank */ + char bank_name[33]; + /* MIDI Bank LSB code */ + uint8_t bank_midi_lsb; + /* MIDI Bank MSB code */ + uint8_t bank_midi_msb; + /* Instruments data of this bank */ + WOPNInstrument ins[128]; +} WOPNBank; + +/* Instrument data file */ +typedef struct OPNIFile +{ + /* Version of instrument file */ + uint16_t version; + /* Is this a percussion instrument */ + uint8_t is_drum; + /* Instrument data */ + WOPNInstrument inst; +} OPNIFile; + +/* Bank data file */ +typedef struct WOPNFile +{ + /* Version of bank file */ + uint16_t version; + /* Count of melodic banks in this file */ + uint16_t banks_count_melodic; + /* Count of percussion banks in this file */ + uint16_t banks_count_percussion; + /* Chip global LFO enable flag and frequency register data */ + uint8_t lfo_freq; + /* Reserved (Enum WOPN_VolumeModel) */ + uint8_t volume_model; + /* dynamically allocated data Melodic banks array */ + WOPNBank *banks_melodic; + /* dynamically allocated data Percussive banks array */ + WOPNBank *banks_percussive; +} WOPNFile; + + +/** + * @brief Initialize blank WOPN data structure with allocated bank data + * @param melodic_banks Count of melodic banks + * @param percussive_banks Count of percussive banks + * @return pointer to heap-allocated WOPN data structure or NULL when out of memory or incorrectly given banks counts + */ +extern WOPNFile *WOPN_Init(uint16_t melodic_banks, uint16_t percussive_banks); + +/** + * @brief Clean up WOPN data file (all allocated bank arrays will be fried too) + * @param file pointer to heap-allocated WOPN data structure + */ +extern void WOPN_Free(WOPNFile *file); + +/** + * @brief Compare two bank entries + * @param bank1 First bank + * @param bank2 Second bank + * @return 1 if banks are equal or 0 if there are different + */ +extern int WOPN_BanksCmp(const WOPNFile *bank1, const WOPNFile *bank2); + + +/** + * @brief Load WOPN bank file from the memory. + * WOPN data structure will be allocated. (don't forget to clear it with WOPN_Free() after use!) + * @param mem Pointer to memory block contains raw WOPN bank file data + * @param length Length of given memory block + * @param error pointer to integer to return an error code. Pass NULL if you don't want to use error codes. + * @return Heap-allocated WOPN file data structure or NULL if any error has occouped + */ +extern WOPNFile *WOPN_LoadBankFromMem(void *mem, size_t length, int *error); + +/** + * @brief Load WOPI instrument file from the memory. + * You must allocate OPNIFile structure by yourself and give the pointer to it. + * @param file Pointer to destinition OPNIFile structure to fill it with parsed data. + * @param mem Pointer to memory block contains raw WOPI instrument file data + * @param length Length of given memory block + * @return 0 if no errors occouped, or an error code of WOPN_ErrorCodes enumeration + */ +extern int WOPN_LoadInstFromMem(OPNIFile *file, void *mem, size_t length); + +/** + * @brief Calculate the size of the output memory block + * @param file Heap-allocated WOPN file data structure + * @param version Destinition version of the file + * @return Size of the raw WOPN file data + */ +extern size_t WOPN_CalculateBankFileSize(WOPNFile *file, uint16_t version); + +/** + * @brief Calculate the size of the output memory block + * @param file Pointer to WOPI file data structure + * @param version Destinition version of the file + * @return Size of the raw WOPI file data + */ +extern size_t WOPN_CalculateInstFileSize(OPNIFile *file, uint16_t version); + +/** + * @brief Write raw WOPN into given memory block + * @param file Heap-allocated WOPN file data structure + * @param dest_mem Destinition memory block pointer + * @param length Length of destinition memory block + * @param version Wanted WOPN version + * @param force_gm Force GM set in saved bank file + * @return Error code or 0 on success + */ +extern int WOPN_SaveBankToMem(WOPNFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm); + +/** + * @brief Write raw WOPI into given memory block + * @param file Pointer to WOPI file data structure + * @param dest_mem Destinition memory block pointer + * @param length Length of destinition memory block + * @param version Wanted WOPI version + * @return Error code or 0 on success + */ +extern int WOPN_SaveInstToMem(OPNIFile *file, void *dest_mem, size_t length, uint16_t version); + +#ifdef __cplusplus +} +#endif + +#endif /* WOPN_FILE_H */ diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index b444f27db..38a1962e8 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2224,6 +2224,10 @@ ADVSNDMNU_RUNPCMRATE = "Run emulator at PCM rate"; ADVSNDMNU_ADLNUMCHIPS = "Number of emulated OPL chips"; ADVSNDMNU_VLMODEL = "Volume model"; ADVSNDMNU_OPNNUMCHIPS = "Number of emulated OPN chips"; +ADVSNDMNU_ADLCUSTOMBANK = "Use custom WOPL bank"; +ADVSNDMNU_OPLBANKFILE = "WOPL Bank file"; +ADVSNDMNU_OPNCUSTOMBANK = "Use custom WOPN bank"; +ADVSNDMNU_OPNBANKFILE = "WOPN Bank file"; // ADLMIDI's emulation cores diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 931ba51a1..0bd45a7d7 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1691,6 +1691,17 @@ OptionMenu ADLBankMenu protected Title "$ADVSNDMNU_OPLBANK" } +OptionMenu ADLMIDICustomBanksMenu protected +{ + Title "$ADVSNDMNU_OPLBANKFILE" +} + +OptionMenu OPNMIDICustomBanksMenu protected +{ + Title "$ADVSNDMNU_OPNBANKFILE" +} + + /*======================================= * * Module Replayer Options Menu @@ -1840,11 +1851,16 @@ OptionMenu ModReplayerOptions protected OptionMenu ADLOptions protected { Title "$ADVSNDMNU_ADLMIDI" - LabeledSubmenu "$ADVSNDMNU_OPLBANK", "adl_bank", "ADLBankMenu" Option "$ADVSNDMNU_OPLCORES", "adl_emulator_id", "ADLOplCores" Option "$ADVSNDMNU_RUNPCMRATE", "adl_run_at_pcm_rate", "OnOff" Slider "$ADVSNDMNU_ADLNUMCHIPS", "adl_chips_count", 1, 32, 1, 0 + Option "$ADVSNDMNU_OPLFULLPAN", "adl_fullpan", "OnOff" Option "$ADVSNDMNU_VLMODEL", "adl_volume_model", "AdlVolumeModels" + StaticText "" + LabeledSubmenu "$ADVSNDMNU_OPLBANK", "adl_bank", "ADLBankMenu" + StaticText "" + Option "$ADVSNDMNU_ADLCUSTOMBANK", "adl_use_custom_bank", "OnOff" + LabeledSubmenu "$ADVSNDMNU_OPLBANKFILE", "adl_custom_bank", "ADLMIDICustomBanksMenu" } OptionMenu OPNOptions protected @@ -1853,6 +1869,10 @@ OptionMenu ModReplayerOptions protected Option "$ADVSNDMNU_OPNCORES", "opn_emulator_id", "OpnCores" Option "$ADVSNDMNU_RUNPCMRATE", "opn_run_at_pcm_rate", "OnOff" Slider "$ADVSNDMNU_OPNNUMCHIPS", "opn_chips_count", 1, 32, 1, 0 + Option "$ADVSNDMNU_OPLFULLPAN", "opn_fullpan", "OnOff" + StaticText "" + Option "$ADVSNDMNU_OPNCUSTOMBANK", "opn_use_custom_bank", "OnOff" + LabeledSubmenu "$ADVSNDMNU_OPNBANKFILE", "opn_custom_bank", "OPNMIDICustomBanksMenu" } /*======================================= @@ -1944,7 +1964,7 @@ OptionMenu VideoModeMenu protected OptionMenu CustomResolutionMenu protected { Title "$VIDMNU_RESPRESETTTL" - + StaticText "$VIDMNU_RESPRESETHEAD" StaticText "" StaticText "$VIDMNU_ASPECT43" @@ -2250,7 +2270,7 @@ OptionMenu "GLTextureGLOptions" protected Option "$GLTEXMNU_TEXFILTER", gl_texture_filter, "FilterModes" Option "$GLTEXMNU_ANISOTROPIC", gl_texture_filter_anisotropic, "Anisotropy" Option "$GLTEXMNU_ENABLEHIRES", gl_texture_usehires, "YesNo" - + ifOption(MMX) { Option "$GLTEXMNU_HQRESIZE", gl_texture_hqresize, "HqResizeModes" diff --git a/wadsrc/static/xg.wopn b/wadsrc/static/xg.wopn index ccb347977..c5d63367e 100644 Binary files a/wadsrc/static/xg.wopn and b/wadsrc/static/xg.wopn differ