diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/adldata.cpp | 470 | ||||
-rw-r--r-- | src/adlmidi.cpp | 245 | ||||
-rw-r--r-- | src/adlmidi_load.cpp | 127 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 1116 | ||||
-rw-r--r-- | src/adlmidi_opl3.cpp | 6 | ||||
-rw-r--r-- | src/adlmidi_private.cpp | 14 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 287 | ||||
-rw-r--r-- | src/dbopl.cpp | 9 | ||||
-rw-r--r-- | src/dbopl.h | 8 |
9 files changed, 1266 insertions, 1016 deletions
diff --git a/src/adldata.cpp b/src/adldata.cpp index 48adaaa..10b452a 100644 --- a/src/adldata.cpp +++ b/src/adldata.cpp @@ -4,7 +4,7 @@ * FROM A NUMBER OF SOURCES, MOSTLY PC GAMES. * PREPROCESSED, CONVERTED, AND POSTPROCESSED OFF-SCREEN. */ -const adldata adl[4351] = +const adldata adl[4355] = { // ,---------+-------- Wave select settings // | ,-------ч-+------ Sustain/release rates // | | ,-----ч-ч-+---- Attack/decay rates @@ -1231,8 +1231,8 @@ const adldata adl[4351] = { 0x30457E0,0x04D67E0, 0x23,0x00, 0xE, +12 }, // 1212: dMM83; hxMM83; musM83; raptM83; Lead 4 (chiffer) { 0x304F7E0,0x04D87E0, 0x23,0x00, 0xE, +12 }, // 1213: dMM83; hxMM83; musM83; raptM83; Lead 4 (chiffer) { 0x10B78A1,0x12BF130, 0x42,0x00, 0x8, +12 }, // 1214: dMM84; hxMM84; musM84; Lead 5 (charang) - { 0x0558060,0x014F2E0, 0x21,0x00, 0x8, +12 }, // 1215: dMM85; hxMM85; musM85; raptM85; skeakernetsM85; Lead 6 (voice); Lead 6 (voice) - { 0x0559020,0x014A2A0, 0x21,0x00, 0x8, +12 }, // 1216: dMM85; hxMM85; musM85; raptM85; skeakernetsM85; Lead 6 (voice); Lead 6 (voice) + { 0x0558060,0x014F2E0, 0x21,0x00, 0x8, +12 }, // 1215: dMM85; hxMM85; musM85; raptM85; Lead 6 (voice) + { 0x0559020,0x014A2A0, 0x21,0x00, 0x8, +12 }, // 1216: dMM85; hxMM85; musM85; raptM85; Lead 6 (voice) { 0x195C120,0x16370B0, 0x43,0x80, 0xA, +12 }, // 1217: dMM86; hxMM86; musM86; raptM86; Lead 7 (5th sawtooth) { 0x19591A0,0x1636131, 0x49,0x00, 0xA, +7 }, // 1218: dMM86; hxMM86; musM86; raptM86; Lead 7 (5th sawtooth) { 0x1075124,0x229FDA0, 0x40,0x00, 0x9, +0 }, // 1219: dMM87; dMM88; hxMM87; hxMM88; musM87; musM88; raptM87; raptM88; * Lead 8 (bass & lead) @@ -1263,7 +1263,7 @@ const adldata adl[4351] = { 0x2ACF907,0x229F90F, 0x1A,0x00, 0x0, +12 }, // 1244: dMM106; hxMM106; musM106; raptM106; skeakernetsM106; Shamisen; Shamisen { 0x153F220,0x0E49122, 0x21,0x00, 0x8, +12 }, // 1245: dMM107; hxMM107; musM107; raptM107; Koto { 0x339F103,0x074D615, 0x4F,0x00, 0x6, +0 }, // 1246: dMM108; hxMM108; musM108; raptM108; Kalimba - { 0x1158930,0x2076B21, 0x42,0x00, 0xA, +12 }, // 1247: dMM109; hxMM109; musM109; raptM109; skeakernetsM109; Bag Pipe; Bag Pipe + { 0x1158930,0x2076B21, 0x42,0x00, 0xA, +12 }, // 1247: dMM109; hxMM109; musM109; raptM109; Bag Pipe { 0x003A130,0x0265221, 0x1F,0x00, 0xE, +12 }, // 1248: dMM110; hxMM110; musM110; raptM110; Fiddle { 0x0134030,0x1166130, 0x13,0x80, 0x8, +12 }, // 1249: dMM111; hxMM111; musM111; raptM111; Shanai { 0x032A113,0x172B212, 0x00,0x80, 0x1, +5 }, // 1250: dMM112; hxMM112; musM112; raptM112; Tinkle Bell @@ -4114,7 +4114,7 @@ const adldata adl[4351] = { 0x0E5B111,0x0B8F211, 0x9C,0x80, 0x0, +0 }, // 4095: skeakernetsM4; Electric Piano (Rhodes) { 0x0C7F437,0x0D7F230, 0x5D,0x0A, 0x8, +12 }, // 4096: skeakernetsM5; Electric Piano (DX-7) { 0x0C7F020,0x0F8F110, 0x1A,0x0F, 0x0, +12 }, // 4097: skeakernetsM5; Electric Piano (DX-7) - { 0x30AF231,0x1F5D130, 0x87,0x00, 0xA, +12 }, // 4098: skeakernetsM6; Harpsichord + { 0x303F232,0x1F6D131, 0x44,0x00, 0x8, +0 }, // 4098: skeakernetsM6; Harpsichord { 0x559F101,0x0F7F111, 0x44,0x08, 0x6, +0 }, // 4099: skeakernetsM7; Clavichord { 0x0F00000,0x4F7F111, 0x3F,0x0D, 0x9, +0 }, // 4100: skeakernetsM7; Clavichord { 0x087F607,0x0E4F231, 0x54,0x08, 0x9, +0 }, // 4101: skeakernetsM8; Celesta @@ -4127,7 +4127,7 @@ const adldata adl[4351] = { 0x0F6F2A4,0x007F08F, 0x40,0x00, 0x1, +0 }, // 4108: skeakernetsM11; Vibraphone { 0x0F6F618,0x0F7E500, 0x63,0x80, 0x6, +12 }, // 4109: skeakernetsM12; Marimba { 0x5A6F407,0x007D802, 0x5B,0x80, 0x0, +12 }, // 4110: skeakernetsM12; Marimba - { 0x696F614,0x055F610, 0x1F,0x00, 0x4, +12 }, // 4111: skeakernetsM13; Xylophone + { 0x096F616,0x0F5F111, 0x1F,0x03, 0x4, +0 }, // 4111: skeakernetsM13; Xylophone { 0x082F307,0x0E3F302, 0x97,0x8A, 0x6, -12 }, // 4112: skeakernetsM14; Tubular Bells { 0x082D307,0x0E3F302, 0x97,0x8A, 0x6, -12 }, // 4113: skeakernetsM14; Tubular Bells { 0x4109130,0x3B5F321, 0x52,0x88, 0x8, +12 }, // 4114: skeakernetsM15; Dulcimer @@ -4187,8 +4187,8 @@ const adldata adl[4351] = { 0x074A201,0x0356411, 0x29,0x07, 0xA, +0 }, // 4168: skeakernetsM45; Pizzicato Strings { 0x022E133,0x0F2F131, 0xA2,0x09, 0xE, +0 }, // 4169: skeakernetsM46; Orchestral Harp { 0x022F132,0x0F2F131, 0x24,0x0A, 0xE, +0 }, // 4170: skeakernetsM46; Orchestral Harp - { 0x4C3A413,0x0B4D215, 0x9B,0x09, 0x8, -12 }, // 4171: skeakernetsM47; Timpani - { 0x0B6F401,0x0B4F211, 0x05,0x09, 0x9, +0 }, // 4172: skeakernetsM47; Timpani + { 0x4C3C413,0x0B4D215, 0x9B,0x09, 0xA, -12 }, // 4171: skeakernetsM47; Timpani + { 0x6BAF900,0x0B4F211, 0x0A,0x09, 0x7, -12 }, // 4172: skeakernetsM47; Timpani { 0x223F832,0x4055421, 0x99,0x8A, 0xC, +0 }, // 4173: skeakernetsM48; String Ensemble1 { 0x433CB32,0x5057521, 0x9B,0x8A, 0xA, +0 }, // 4174: skeakernetsM48; String Ensemble1 { 0x5059022,0x1055521, 0x5B,0x85, 0x0, +0 }, // 4175: skeakernetsM49; String Ensemble 2 @@ -4219,7 +4219,7 @@ const adldata adl[4351] = { 0x0A66120,0x0976120, 0x9B,0x08, 0xE, +12 }, // 4200: skeakernetsM63; Synth Brass 2 { 0x0A66120,0x0976120, 0x9B,0x08, 0xE, +12 }, // 4201: skeakernetsM63; Synth Brass 2 { 0x0F37010,0x1F65051, 0x51,0x04, 0xA, +12 }, // 4202: skeakernetsM64; Soprano Sax - { 0x1067020,0x1165230, 0x88,0x00, 0x6, +12 }, // 4203: skeakernetsM65; Alto Sax + { 0x1067021,0x1165231, 0x8A,0x00, 0x6, +0 }, // 4203: skeakernetsM65; Alto Sax { 0x00B9820,0x10B5330, 0x8E,0x00, 0xA, +12 }, // 4204: skeakernetsM66; Tenor Sax { 0x10B8020,0x11B6330, 0x87,0x00, 0x8, +12 }, // 4205: skeakernetsM67; Baritone Sax { 0x0235030,0x0076C62, 0x58,0x08, 0xA, +12 }, // 4206: skeakernetsM68; Oboe @@ -4246,129 +4246,133 @@ const adldata adl[4351] = { 0x40457E1,0x03D67E0, 0x23,0x00, 0xE, +12 }, // 4227: skeakernetsM83; Lead 4 (chiffer) { 0x504F7E1,0x03D87E0, 0x23,0x00, 0xE, +12 }, // 4228: skeakernetsM83; Lead 4 (chiffer) { 0x32B7320,0x12BF131, 0x40,0x00, 0x8, +0 }, // 4229: skeakernetsM84; Lead 5 (charang) - { 0x195C120,0x1637030, 0x43,0x80, 0xA, +12 }, // 4230: skeakernetsM86; Lead 7 (5th sawtooth) - { 0x1959120,0x1636131, 0x49,0x00, 0xA, +7 }, // 4231: skeakernetsM86; Lead 7 (5th sawtooth) - { 0x132ED10,0x3E7D210, 0x87,0x08, 0x6, +12 }, // 4232: skeakernetsM87; Lead 8 brass - { 0x132ED10,0x3E7D210, 0x87,0x0D, 0x6, +12 }, // 4233: skeakernetsM87; Lead 8 brass - { 0x2946374,0x005A0A1, 0xA5,0x05, 0x2, +0 }, // 4234: skeakernetsM88; Pad 1 new age - { 0x2055F02,0x004FFE1, 0xA8,0x05, 0x0, +0 }, // 4235: skeakernetsM88; Pad 1 new age - { 0x00521A1,0x0053360, 0xC0,0x00, 0x9, +12 }, // 4236: skeakernetsM89; Pad 2 (warm) - { 0x0052161,0x00533E0, 0xC0,0x00, 0x7, +12 }, // 4237: skeakernetsM89; Pad 2 (warm) - { 0x2A5A120,0x196A120, 0x95,0x05, 0xC, +12 }, // 4238: skeakernetsM90; Pad 3 (polysynth) - { 0x2A5A120,0x196A120, 0x95,0x05, 0xC, +12 }, // 4239: skeakernetsM90; Pad 3 (polysynth) - { 0x005F0E0,0x0548160, 0x44,0x00, 0xB, +12 }, // 4240: skeakernetsM91; Pad 4 (choir) - { 0x105F0E0,0x0547160, 0x44,0x80, 0xB, +12 }, // 4241: skeakernetsM91; Pad 4 (choir) - { 0x0336183,0x05452E0, 0xA7,0x00, 0x6, +12 }, // 4242: skeakernetsM92; Pad 5 (bowed glass) - { 0x13351A3,0x05452E0, 0xA7,0x00, 0x0, +12 }, // 4243: skeakernetsM92; Pad 5 (bowed glass) - { 0x2529082,0x1534340, 0x9D,0x80, 0xC, +12 }, // 4244: skeakernetsM93; Pad 6 (metal) - { 0x2529081,0x0534340, 0x9D,0x80, 0xC, +12 }, // 4245: skeakernetsM93; Pad 6 (metal) - { 0x2345231,0x2135120, 0x98,0x00, 0x6, +0 }, // 4246: skeakernetsM94; Pad 7 halo - { 0x410F422,0x1233231, 0x20,0x00, 0xA, +0 }, // 4247: skeakernetsM94; Pad 7 halo - { 0x1521161,0x1632060, 0x90,0x80, 0x8, +12 }, // 4248: skeakernetsM95; Pad 8 (sweep) - { 0x1521160,0x1632060, 0x90,0x80, 0x8, +12 }, // 4249: skeakernetsM95; Pad 8 (sweep) - { 0x157B260,0x019F803, 0x04,0x40, 0x7, +12 }, // 4250: skeakernetsM96; FX 1 (rain) - { 0x157B260,0x0145112, 0x04,0x40, 0x7, +12 }, // 4251: skeakernetsM96; FX 1 (rain) - { 0x2322122,0x0133221, 0x8C,0x92, 0x6, +0 }, // 4252: skeakernetsM97; FX 2 soundtrack - { 0x0032121,0x0133122, 0x93,0x48, 0x2, +7 }, // 4253: skeakernetsM97; FX 2 soundtrack - { 0x074F624,0x0249303, 0xC0,0x0D, 0x0, +0 }, // 4254: skeakernetsM98; FX 3 (crystal) - { 0x074F624,0x0249303, 0xC0,0x0D, 0x0, +0 }, // 4255: skeakernetsM98; FX 3 (crystal) - { 0x3D2C091,0x1D2D130, 0x8E,0x03, 0x0, +12 }, // 4256: skeakernetsM99; FX 4 (atmosphere) - { 0x0D2D090,0x1D23131, 0x8E,0x03, 0x0, +12 }, // 4257: skeakernetsM99; FX 4 (atmosphere) - { 0x5F29052,0x0F2C240, 0x96,0x06, 0x8, +12 }, // 4258: skeakernetsM100; FX 5 (brightness) - { 0x1F19010,0x0F2C240, 0x1A,0x06, 0x6, +12 }, // 4259: skeakernetsM100; FX 5 (brightness) - { 0x05213E1,0x2131371, 0x1A,0x88, 0x7, +0 }, // 4260: skeakernetsM101; FX 6 (goblin) - { 0x0521363,0x2131331, 0x1A,0x8D, 0x7, +0 }, // 4261: skeakernetsM101; FX 6 (goblin) - { 0x0B67060,0x0928031, 0x9C,0x11, 0xA, +12 }, // 4262: skeakernetsM102; FX 7 (echo drops) - { 0x0057F20,0x0038F61, 0x9C,0x11, 0xA, +12 }, // 4263: skeakernetsM102; FX 7 (echo drops) - { 0x0025511,0x1748201, 0x94,0x06, 0xE, +0 }, // 4264: skeakernetsM103; * FX 8 (star-theme) - { 0x2045501,0x2445501, 0x15,0x0D, 0xA, +0 }, // 4265: skeakernetsM103; * FX 8 (star-theme) - { 0x0B37120,0x5F48220, 0x1B,0x08, 0x2, +12 }, // 4266: skeakernetsM104; Sitar - { 0x2B37101,0x5F48220, 0x90,0x08, 0x6, +12 }, // 4267: skeakernetsM104; Sitar - { 0x0127530,0x6F4F310, 0x0D,0x0A, 0x6, +12 }, // 4268: skeakernetsM105; Banjo - { 0x332F320,0x6E49423, 0x0E,0x08, 0x8, +0 }, // 4269: skeakernetsM107; Koto - { 0x0328413,0x073B410, 0xA1,0x00, 0xF, +12 }, // 4270: skeakernetsM108; Kalimba - { 0x302A130,0x0266221, 0x1E,0x00, 0xE, +0 }, // 4271: skeakernetsM110; Fiddle - { 0x0136030,0x1169130, 0x12,0x80, 0x8, +12 }, // 4272: skeakernetsM111; Shanai - { 0x032A115,0x172B212, 0x00,0x80, 0x1, +5 }, // 4273: skeakernetsM112; Tinkle Bell - { 0x4046303,0x005A901, 0xCA,0x08, 0x6, +12 }, // 4274: skeakernetsM114; Steel Drums - { 0x0045413,0x005A601, 0x51,0x08, 0xA, +0 }, // 4275: skeakernetsM114; Steel Drums - { 0x6D1F817,0x098F611, 0xA7,0x00, 0x6, +12 }, // 4276: skeakernetsM115; Woodblock - { 0x008F312,0x004F600, 0x08,0xC8, 0x4, -12 }, // 4277: skeakernetsM116; Taiko Drum (new) - { 0x27CFA01,0x004F200, 0x08,0x08, 0x0, +0 }, // 4278: skeakernetsM116; Taiko Drum (new) - { 0x0C8A820,0x0B7E601, 0x0B,0x00, 0x0, +0 }, // 4279: skeakernetsM117; Melodic Tom - { 0x518F890,0x0E5D310, 0x00,0x00, 0x8, -12 }, // 4280: skeakernetsM118; Synth Drum - { 0x050F011,0x0E5F510, 0x00,0xC8, 0xA, +0 }, // 4281: skeakernetsM118; Synth Drum - { 0x2114109,0x51D2101, 0x05,0x80, 0xA, +0 }, // 4282: skeakernetsM119; Reverse Cymbal - { 0x2114108,0x31D2101, 0x05,0x80, 0xA, +12 }, // 4283: skeakernetsM119; Reverse Cymbal - { 0x4543310,0x3574515, 0x19,0x03, 0xE, +12 }, // 4284: skeakernetsM120; Guitar Fret Noise - { 0x00437D2,0x0343471, 0xA1,0x07, 0xC, +0 }, // 4285: skeakernetsM121; Breath Noise - { 0x0F0F00C,0x0F66700, 0x00,0xCD, 0xE, +0 }, // 4286: skeakernetsM121; Breath Noise - { 0x200C327,0x6021300, 0x80,0x08, 0xE, -23 }, // 4287: skeakernetsM122; Seashore - { 0x200C32B,0x6021300, 0x80,0x08, 0xE, -24 }, // 4288: skeakernetsM122; Seashore - { 0x003EBD7,0x06845D8, 0xD4,0x00, 0x7, +12 }, // 4289: skeakernetsM123; Bird Tweet - { 0x62FDA20,0x614B009, 0x42,0x48, 0x4, -24 }, // 4290: skeakernetsM124; Telephone Ring - { 0x62FDA20,0x614B009, 0x82,0x48, 0x4, -20 }, // 4291: skeakernetsM124; Telephone Ring - { 0x101FE30,0x6142120, 0x00,0x00, 0xC, -36 }, // 4292: skeakernetsM125; Helicopter - { 0x6019460,0x1142120, 0x26,0x00, 0xC, -14 }, // 4293: skeakernetsM125; Helicopter - { 0x200832F,0x6044020, 0x80,0x00, 0xE, -36 }, // 4294: skeakernetsM126; Applause - { 0x200832F,0x6044020, 0x80,0x00, 0xE, -35 }, // 4295: skeakernetsM126; Applause - { 0x230732F,0x6E6F400, 0x00,0x00, 0xE, +0 }, // 4296: skeakernetsM127; Gun Shot - { 0x057FB00,0x046F800, 0x00,0x00, 0x0, +12 }, // 4297: skeakernetsP35; Acoustic Bass Drum - { 0x287F702,0x678F802, 0x80,0x88, 0xE, +12 }, // 4298: skeakernetsP37; Slide Stick - { 0x2F7F602,0x0F8F802, 0x00,0x88, 0xE, +12 }, // 4299: skeakernetsP37; Slide Stick - { 0x05476C1,0x30892C5, 0x80,0x08, 0x0, +0 }, // 4300: skeakernetsP39; ÿHand Clap - { 0x05477C1,0x30892C5, 0x00,0x08, 0xA, -2 }, // 4301: skeakernetsP39; ÿHand Clap - { 0x508F601,0x104F600, 0x08,0x00, 0x6, +0 }, // 4302: skeakernetsP41; skeakernetsP43; ÿHigh Floor Tom; ÿLow Floor Tom - { 0x254F307,0x307F905, 0x04,0x0B, 0x6, -5 }, // 4303: skeakernetsP42; Closed High-Hat - { 0x254F307,0x207F905, 0x04,0x0B, 0x8, +0 }, // 4304: skeakernetsP42; Closed High-Hat - { 0x254D307,0x3288905, 0x04,0x08, 0xA, -5 }, // 4305: skeakernetsP44; Pedal High Hat - { 0x508F601,0x104F600, 0x0C,0x00, 0x8, +0 }, // 4306: skeakernetsP45; skeakernetsP47; skeakernetsP48; skeakernetsP50; ÿHigh Tom; ÿHigh-Mid Tom; ÿLow Tom; ÿLow-Mid Tom - { 0x292F108,0x354F201, 0x00,0x08, 0x8, +12 }, // 4307: skeakernetsP49; Crash Cymbal 1 - { 0x292F108,0x354F201, 0x00,0x08, 0x8, +12 }, // 4308: skeakernetsP49; Crash Cymbal 1 - { 0x210F509,0x305FE03, 0x8A,0x88, 0xE, +12 }, // 4309: skeakernetsP51; Ride Cymbal 1 - { 0x200F508,0x305FE03, 0xC7,0x88, 0xC, +12 }, // 4310: skeakernetsP51; Ride Cymbal 1 - { 0x283E108,0x334D700, 0x00,0x08, 0x8, +12 }, // 4311: skeakernetsP52; Chinses Cymbal - { 0x283E109,0x334D500, 0x00,0x08, 0x8, +11 }, // 4312: skeakernetsP52; Chinses Cymbal - { 0x2E1F119,0x3F3F11B, 0x04,0x08, 0x8, +0 }, // 4313: skeakernetsP53; Ride Bell - { 0x2777603,0x3679601, 0x87,0x08, 0x6, +12 }, // 4314: skeakernetsP54; Tambourine - { 0x277C643,0x3679601, 0x87,0x08, 0xE, +12 }, // 4315: skeakernetsP54; Tambourine - { 0x251F206,0x263C504, 0x04,0x09, 0xA, +0 }, // 4316: skeakernetsP55; Splash Cymbal - { 0x241F287,0x353B502, 0x05,0x09, 0xA, +1 }, // 4317: skeakernetsP55; Splash Cymbal - { 0x366F905,0x099F701, 0x00,0x00, 0xC, +12 }, // 4318: skeakernetsP56; Cowbell - { 0x292F108,0x354F201, 0x00,0x03, 0x8, +12 }, // 4319: skeakernetsP57; Crash Cymbal 2 - { 0x292F108,0x354F201, 0x00,0x03, 0x8, +12 }, // 4320: skeakernetsP57; Crash Cymbal 2 - { 0x422F120,0x056B40E, 0x81,0x00, 0xA, +12 }, // 4321: skeakernetsP58; Vibraslap - { 0x212FD04,0x305FD03, 0x01,0x00, 0x8, +12 }, // 4322: skeakernetsP59; Ride Cymbal 2 - { 0x2A8F9E3,0x0779643, 0x1E,0x08, 0x2, +6 }, // 4323: skeakernetsP60; High Bongo (New) - { 0x0A5F7E8,0x0D89949, 0xDE,0x00, 0x0, +0 }, // 4324: skeakernetsP60; High Bongo (New) - { 0x2A8F9E3,0x0779643, 0x1E,0x00, 0xE, +12 }, // 4325: skeakernetsP61; Low Bongo (New) - { 0x0A5F7E9,0x0D8994A, 0xDE,0x08, 0xC, +0 }, // 4326: skeakernetsP61; Low Bongo (New) - { 0x0A8F7E9,0x5D8990A, 0x08,0x00, 0xC, +0 }, // 4327: skeakernetsP62; Mute high conga (New) - { 0x0A5F7E9,0x0D8994A, 0x29,0x08, 0xC, +10 }, // 4328: skeakernetsP62; Mute high conga (New) - { 0x2A8F9E2,0x0779642, 0x1E,0x00, 0xE, +8 }, // 4329: skeakernetsP63; skeakernetsP64; Low Conga (New); Open High Conga (New) - { 0x0A5F7E9,0x5D8994A, 0x08,0x00, 0xC, +0 }, // 4330: skeakernetsP63; skeakernetsP64; Low Conga (New); Open High Conga (New) - { 0x456FB02,0x017F700, 0x81,0x00, 0x0, +12 }, // 4331: skeakernetsP65; skeakernetsP66; High Timbale; Low Timbale - { 0x367FD01,0x098F601, 0x00,0x08, 0x8, +12 }, // 4332: skeakernetsP67; skeakernetsP68; High Agogo; Low Agogo - { 0x367FD10,0x098F901, 0x00,0x0D, 0x8, +6 }, // 4333: skeakernetsP67; High Agogo - { 0x367FD10,0x098F901, 0x00,0x0D, 0x8, +11 }, // 4334: skeakernetsP68; Low Agogo - { 0x098600F,0x3FC8590, 0x08,0xC0, 0xE, +12 }, // 4335: skeakernetsP70; Maracas - { 0x009F020,0x37DA588, 0x07,0x00, 0xA, +12 }, // 4336: skeakernetsP71; Short Whistle - { 0x00FC020,0x32DA5A8, 0x07,0x00, 0xA, +12 }, // 4337: skeakernetsP72; Long Whistle - { 0x106F680,0x016F610, 0x00,0x00, 0xC, +0 }, // 4338: skeakernetsP73; ÿShort Guiro - { 0x20F6F00,0x20F6F00, 0x00,0x00, 0x0, +0 }, // 4339: skeakernetsP73; ÿShort Guiro - { 0x106F680,0x016F610, 0x00,0x00, 0x6, +0 }, // 4340: skeakernetsP74; ÿLong Guiro - { 0x20F4F00,0x20F4F00, 0x00,0x00, 0x6, +0 }, // 4341: skeakernetsP74; ÿLong Guiro - { 0x0D1F815,0x078F512, 0x44,0x00, 0x8, +12 }, // 4342: skeakernetsP75; Claves - { 0x1DC5D01,0x06FF79F, 0x0B,0x00, 0xA, +12 }, // 4343: skeakernetsP78; Mute Cuica - { 0x1C7C900,0x05FF49F, 0x07,0x00, 0xA, +12 }, // 4344: skeakernetsP79; Open Cuica - { 0x160F2C6,0x07AF4D4, 0x4F,0x80, 0x8, +12 }, // 4345: skeakernetsP80; Mute Triangle - { 0x160F286,0x0B7F294, 0x4F,0x80, 0x8, +12 }, // 4346: skeakernetsP81; Open Triangle - { 0x227A305,0x36A560A, 0x87,0x08, 0xE, +12 }, // 4347: skeakernetsP82; (GS & XG) Shaker - { 0x247C345,0x3697809, 0x87,0x08, 0xE, +12 }, // 4348: skeakernetsP82; (GS & XG) Shaker - { 0x4755406,0x3667601, 0x87,0x08, 0x6, +12 }, // 4349: skeakernetsP83; (GS & XG) Jingle Bells - { 0x275A346,0x3667601, 0x87,0x08, 0x6, +12 }, // 4350: skeakernetsP83; (GS & XG) Jingle Bells + { 0x5029071,0x0069060, 0x96,0x09, 0x8, +12 }, // 4230: skeakernetsM85; Lead 6 (Voice) + { 0x1019030,0x0069060, 0x1A,0x09, 0x6, +12 }, // 4231: skeakernetsM85; Lead 6 (Voice) + { 0x195C120,0x1637030, 0x43,0x80, 0xA, +12 }, // 4232: skeakernetsM86; Lead 7 (5th sawtooth) + { 0x1959120,0x1636131, 0x49,0x00, 0xA, +7 }, // 4233: skeakernetsM86; Lead 7 (5th sawtooth) + { 0x132ED10,0x3E7D210, 0x87,0x08, 0x6, +12 }, // 4234: skeakernetsM87; Lead 8 brass + { 0x132ED10,0x3E7D210, 0x87,0x0D, 0x6, +12 }, // 4235: skeakernetsM87; Lead 8 brass + { 0x2946374,0x005A0A1, 0xA5,0x05, 0x2, +0 }, // 4236: skeakernetsM88; Pad 1 new age + { 0x2055F02,0x004FFE1, 0xA8,0x05, 0x0, +0 }, // 4237: skeakernetsM88; Pad 1 new age + { 0x00521A1,0x0053360, 0xC0,0x00, 0x9, +12 }, // 4238: skeakernetsM89; Pad 2 (warm) + { 0x0052161,0x00533E0, 0xC0,0x00, 0x7, +12 }, // 4239: skeakernetsM89; Pad 2 (warm) + { 0x2A5A120,0x196A120, 0x95,0x05, 0xC, +12 }, // 4240: skeakernetsM90; Pad 3 (polysynth) + { 0x2A5A120,0x196A120, 0x95,0x05, 0xC, +12 }, // 4241: skeakernetsM90; Pad 3 (polysynth) + { 0x005F0E0,0x0548160, 0x44,0x00, 0xB, +12 }, // 4242: skeakernetsM91; Pad 4 (choir) + { 0x105F0E0,0x0547160, 0x44,0x80, 0xB, +12 }, // 4243: skeakernetsM91; Pad 4 (choir) + { 0x0336183,0x05452E0, 0xA7,0x00, 0x6, +12 }, // 4244: skeakernetsM92; Pad 5 (bowed glass) + { 0x13351A3,0x05452E0, 0xA7,0x00, 0x0, +12 }, // 4245: skeakernetsM92; Pad 5 (bowed glass) + { 0x2529082,0x1534340, 0x9D,0x80, 0xC, +12 }, // 4246: skeakernetsM93; Pad 6 (metal) + { 0x2529081,0x0534340, 0x9D,0x80, 0xC, +12 }, // 4247: skeakernetsM93; Pad 6 (metal) + { 0x2345231,0x2135120, 0x98,0x00, 0x6, +0 }, // 4248: skeakernetsM94; Pad 7 halo + { 0x410F422,0x1233231, 0x20,0x00, 0xA, +0 }, // 4249: skeakernetsM94; Pad 7 halo + { 0x1521161,0x1632060, 0x90,0x80, 0x8, +12 }, // 4250: skeakernetsM95; Pad 8 (sweep) + { 0x1521160,0x1632060, 0x90,0x80, 0x8, +12 }, // 4251: skeakernetsM95; Pad 8 (sweep) + { 0x157B260,0x019F803, 0x04,0x40, 0x7, +12 }, // 4252: skeakernetsM96; FX 1 (rain) + { 0x157B260,0x0145112, 0x04,0x40, 0x7, +12 }, // 4253: skeakernetsM96; FX 1 (rain) + { 0x2322122,0x0133221, 0x8C,0x92, 0x6, +0 }, // 4254: skeakernetsM97; FX 2 soundtrack + { 0x0032121,0x0133122, 0x93,0x48, 0x2, +7 }, // 4255: skeakernetsM97; FX 2 soundtrack + { 0x074F624,0x0249303, 0xC0,0x0D, 0x0, +0 }, // 4256: skeakernetsM98; FX 3 (crystal) + { 0x074F624,0x0249303, 0xC0,0x0D, 0x0, +0 }, // 4257: skeakernetsM98; FX 3 (crystal) + { 0x3D2C091,0x1D2D130, 0x8E,0x03, 0x0, +12 }, // 4258: skeakernetsM99; FX 4 (atmosphere) + { 0x0D2D090,0x1D23131, 0x8E,0x03, 0x0, +12 }, // 4259: skeakernetsM99; FX 4 (atmosphere) + { 0x5F29052,0x0F2C240, 0x96,0x06, 0x8, +12 }, // 4260: skeakernetsM100; FX 5 (brightness) + { 0x1F19010,0x0F2C240, 0x1A,0x06, 0x6, +12 }, // 4261: skeakernetsM100; FX 5 (brightness) + { 0x05213E1,0x2131371, 0x1A,0x88, 0x7, +0 }, // 4262: skeakernetsM101; FX 6 (goblin) + { 0x0521363,0x2131331, 0x1A,0x8D, 0x7, +0 }, // 4263: skeakernetsM101; FX 6 (goblin) + { 0x0B67060,0x0928031, 0x9C,0x11, 0xA, +12 }, // 4264: skeakernetsM102; FX 7 (echo drops) + { 0x0057F20,0x0038F61, 0x9C,0x11, 0xA, +12 }, // 4265: skeakernetsM102; FX 7 (echo drops) + { 0x0025511,0x1748201, 0x94,0x06, 0xE, +0 }, // 4266: skeakernetsM103; * FX 8 (star-theme) + { 0x2045501,0x2445501, 0x15,0x0D, 0xA, +0 }, // 4267: skeakernetsM103; * FX 8 (star-theme) + { 0x0B37120,0x5F48220, 0x1B,0x08, 0x2, +12 }, // 4268: skeakernetsM104; Sitar + { 0x2B37101,0x5F48220, 0x90,0x08, 0x6, +12 }, // 4269: skeakernetsM104; Sitar + { 0x0127530,0x6F4F310, 0x0D,0x0A, 0x6, +12 }, // 4270: skeakernetsM105; Banjo + { 0x332F320,0x6E49423, 0x0E,0x08, 0x8, +0 }, // 4271: skeakernetsM107; Koto + { 0x0328413,0x073B410, 0xA1,0x00, 0xF, +12 }, // 4272: skeakernetsM108; Kalimba + { 0x1397931,0x2099B22, 0x80,0x00, 0x6, +0 }, // 4273: skeakernetsM109; Bag Pipe + { 0x2137931,0x1079B22, 0x42,0xC2, 0xA, +0 }, // 4274: skeakernetsM109; Bag Pipe + { 0x302A130,0x0266221, 0x1E,0x00, 0xE, +0 }, // 4275: skeakernetsM110; Fiddle + { 0x0136030,0x1169130, 0x12,0x80, 0x8, +12 }, // 4276: skeakernetsM111; Shanai + { 0x032A115,0x172B212, 0x00,0x80, 0x1, +5 }, // 4277: skeakernetsM112; Tinkle Bell + { 0x4046303,0x005A901, 0xCA,0x08, 0x6, +12 }, // 4278: skeakernetsM114; Steel Drums + { 0x0045413,0x005A601, 0x51,0x08, 0xA, +0 }, // 4279: skeakernetsM114; Steel Drums + { 0x6D1F817,0x098F611, 0xA7,0x00, 0x6, +12 }, // 4280: skeakernetsM115; Woodblock + { 0x008F312,0x004F600, 0x08,0xC8, 0x4, -12 }, // 4281: skeakernetsM116; Taiko Drum (new) + { 0x27CFA01,0x004F200, 0x08,0x08, 0x0, +0 }, // 4282: skeakernetsM116; Taiko Drum (new) + { 0x0C8A820,0x0B7E601, 0x0B,0x00, 0x0, +0 }, // 4283: skeakernetsM117; Melodic Tom + { 0x518F890,0x0E7F310, 0x00,0x00, 0x8, -12 }, // 4284: skeakernetsM118; Synth Drum + { 0x250F610,0x0E7F510, 0x00,0xC8, 0x6, +0 }, // 4285: skeakernetsM118; Synth Drum + { 0x2114109,0x51D2101, 0x05,0x80, 0xA, +0 }, // 4286: skeakernetsM119; Reverse Cymbal + { 0x2114108,0x31D2101, 0x05,0x80, 0xA, +12 }, // 4287: skeakernetsM119; Reverse Cymbal + { 0x4543310,0x3574515, 0x19,0x03, 0xE, +12 }, // 4288: skeakernetsM120; Guitar Fret Noise + { 0x00437D2,0x0343471, 0xA1,0x07, 0xC, +0 }, // 4289: skeakernetsM121; Breath Noise + { 0x0F0F00C,0x0F66700, 0x00,0xCD, 0xE, +0 }, // 4290: skeakernetsM121; Breath Noise + { 0x200C327,0x6021300, 0x80,0x08, 0xE, -23 }, // 4291: skeakernetsM122; Seashore + { 0x200C32B,0x6021300, 0x80,0x08, 0xE, -24 }, // 4292: skeakernetsM122; Seashore + { 0x003EBD7,0x06845D8, 0xD4,0x00, 0x7, +12 }, // 4293: skeakernetsM123; Bird Tweet + { 0x62FDA20,0x614B009, 0x42,0x48, 0x4, -24 }, // 4294: skeakernetsM124; Telephone Ring + { 0x62FDA20,0x614B009, 0x82,0x48, 0x4, -20 }, // 4295: skeakernetsM124; Telephone Ring + { 0x101FE30,0x6142120, 0x00,0x00, 0xC, -36 }, // 4296: skeakernetsM125; Helicopter + { 0x6019460,0x1142120, 0x26,0x00, 0xC, -14 }, // 4297: skeakernetsM125; Helicopter + { 0x200832F,0x6044020, 0x80,0x00, 0xE, -36 }, // 4298: skeakernetsM126; Applause + { 0x200832F,0x6044020, 0x80,0x00, 0xE, -35 }, // 4299: skeakernetsM126; Applause + { 0x230732F,0x6E6F400, 0x00,0x00, 0xE, +0 }, // 4300: skeakernetsM127; Gun Shot + { 0x057FB00,0x046F800, 0x00,0x00, 0x0, +12 }, // 4301: skeakernetsP35; Acoustic Bass Drum + { 0x287F702,0x678F802, 0x80,0x88, 0xE, +12 }, // 4302: skeakernetsP37; Slide Stick + { 0x2F7F602,0x0F8F802, 0x00,0x88, 0xE, +12 }, // 4303: skeakernetsP37; Slide Stick + { 0x05476C1,0x30892C5, 0x80,0x08, 0x0, +0 }, // 4304: skeakernetsP39; ÿHand Clap + { 0x05477C1,0x30892C5, 0x00,0x08, 0xA, -2 }, // 4305: skeakernetsP39; ÿHand Clap + { 0x508F601,0x104F600, 0x08,0x00, 0x6, +0 }, // 4306: skeakernetsP41; skeakernetsP43; ÿHigh Floor Tom; ÿLow Floor Tom + { 0x254F307,0x307F905, 0x04,0x0B, 0x6, -5 }, // 4307: skeakernetsP42; Closed High-Hat + { 0x254F307,0x207F905, 0x04,0x0B, 0x8, +0 }, // 4308: skeakernetsP42; Closed High-Hat + { 0x254D307,0x3288905, 0x04,0x08, 0xA, -5 }, // 4309: skeakernetsP44; Pedal High Hat + { 0x508F601,0x104F600, 0x0C,0x00, 0x8, +0 }, // 4310: skeakernetsP45; skeakernetsP47; skeakernetsP48; skeakernetsP50; ÿHigh Tom; ÿHigh-Mid Tom; ÿLow Tom; ÿLow-Mid Tom + { 0x292F108,0x354F201, 0x00,0x08, 0x8, +12 }, // 4311: skeakernetsP49; Crash Cymbal 1 + { 0x292F108,0x354F201, 0x00,0x08, 0x8, +12 }, // 4312: skeakernetsP49; Crash Cymbal 1 + { 0x210F509,0x305FE03, 0x8A,0x88, 0xE, +12 }, // 4313: skeakernetsP51; Ride Cymbal 1 + { 0x200F508,0x305FE03, 0xC7,0x88, 0xC, +12 }, // 4314: skeakernetsP51; Ride Cymbal 1 + { 0x283E108,0x334D700, 0x00,0x08, 0x8, +12 }, // 4315: skeakernetsP52; Chinses Cymbal + { 0x283E109,0x334D500, 0x00,0x08, 0x8, +11 }, // 4316: skeakernetsP52; Chinses Cymbal + { 0x2E1F119,0x3F3F11B, 0x04,0x08, 0x8, +0 }, // 4317: skeakernetsP53; Ride Bell + { 0x2777603,0x3679601, 0x87,0x08, 0x6, +12 }, // 4318: skeakernetsP54; Tambourine + { 0x277C643,0x3679601, 0x87,0x08, 0xE, +12 }, // 4319: skeakernetsP54; Tambourine + { 0x251F206,0x263C504, 0x04,0x09, 0xA, +0 }, // 4320: skeakernetsP55; Splash Cymbal + { 0x241F287,0x353B502, 0x05,0x09, 0xA, +1 }, // 4321: skeakernetsP55; Splash Cymbal + { 0x366F905,0x099F701, 0x00,0x00, 0xC, +12 }, // 4322: skeakernetsP56; Cowbell + { 0x292F108,0x354F201, 0x00,0x03, 0x8, +12 }, // 4323: skeakernetsP57; Crash Cymbal 2 + { 0x292F108,0x354F201, 0x00,0x03, 0x8, +12 }, // 4324: skeakernetsP57; Crash Cymbal 2 + { 0x422F120,0x056B40E, 0x81,0x00, 0xA, +12 }, // 4325: skeakernetsP58; Vibraslap + { 0x212FD04,0x305FD03, 0x01,0x00, 0x8, +12 }, // 4326: skeakernetsP59; Ride Cymbal 2 + { 0x2A8F9E3,0x0779643, 0x1E,0x08, 0x2, +6 }, // 4327: skeakernetsP60; High Bongo (New) + { 0x0A5F7E8,0x0D89949, 0xDE,0x00, 0x0, +0 }, // 4328: skeakernetsP60; High Bongo (New) + { 0x2A8F9E3,0x0779643, 0x1E,0x00, 0xE, +12 }, // 4329: skeakernetsP61; Low Bongo (New) + { 0x0A5F7E9,0x0D8994A, 0xDE,0x08, 0xC, +0 }, // 4330: skeakernetsP61; Low Bongo (New) + { 0x0A8F7E9,0x5D8990A, 0x08,0x00, 0xC, +0 }, // 4331: skeakernetsP62; Mute high conga (New) + { 0x0A5F7E9,0x0D8994A, 0x29,0x08, 0xC, +10 }, // 4332: skeakernetsP62; Mute high conga (New) + { 0x2A8F9E2,0x0779642, 0x1E,0x00, 0xE, +8 }, // 4333: skeakernetsP63; skeakernetsP64; Low Conga (New); Open High Conga (New) + { 0x0A5F7E9,0x5D8994A, 0x08,0x00, 0xC, +0 }, // 4334: skeakernetsP63; skeakernetsP64; Low Conga (New); Open High Conga (New) + { 0x456FB02,0x017F700, 0x81,0x00, 0x0, +12 }, // 4335: skeakernetsP65; skeakernetsP66; High Timbale; Low Timbale + { 0x367FD01,0x098F601, 0x00,0x08, 0x8, +12 }, // 4336: skeakernetsP67; skeakernetsP68; High Agogo; Low Agogo + { 0x367FD10,0x098F901, 0x00,0x0D, 0x8, +6 }, // 4337: skeakernetsP67; High Agogo + { 0x367FD10,0x098F901, 0x00,0x0D, 0x8, +11 }, // 4338: skeakernetsP68; Low Agogo + { 0x098600F,0x3FC8590, 0x08,0xC0, 0xE, +12 }, // 4339: skeakernetsP70; Maracas + { 0x009F020,0x37DA588, 0x07,0x00, 0xA, +12 }, // 4340: skeakernetsP71; Short Whistle + { 0x00FC020,0x32DA5A8, 0x07,0x00, 0xA, +12 }, // 4341: skeakernetsP72; Long Whistle + { 0x106F680,0x016F610, 0x00,0x00, 0xC, +0 }, // 4342: skeakernetsP73; ÿShort Guiro + { 0x20F6F00,0x20F6F00, 0x00,0x00, 0x0, +0 }, // 4343: skeakernetsP73; ÿShort Guiro + { 0x106F680,0x016F610, 0x00,0x00, 0x6, +0 }, // 4344: skeakernetsP74; ÿLong Guiro + { 0x20F4F00,0x20F4F00, 0x00,0x00, 0x6, +0 }, // 4345: skeakernetsP74; ÿLong Guiro + { 0x0D1F815,0x078F512, 0x44,0x00, 0x8, +12 }, // 4346: skeakernetsP75; Claves + { 0x1DC5D01,0x06FF79F, 0x0B,0x00, 0xA, +12 }, // 4347: skeakernetsP78; Mute Cuica + { 0x1C7C900,0x05FF49F, 0x07,0x00, 0xA, +12 }, // 4348: skeakernetsP79; Open Cuica + { 0x160F2C6,0x07AF4D4, 0x4F,0x80, 0x8, +12 }, // 4349: skeakernetsP80; Mute Triangle + { 0x160F286,0x0B7F294, 0x4F,0x80, 0x8, +12 }, // 4350: skeakernetsP81; Open Triangle + { 0x227A305,0x36A560A, 0x87,0x08, 0xE, +12 }, // 4351: skeakernetsP82; (GS & XG) Shaker + { 0x247C345,0x3697809, 0x87,0x08, 0xE, +12 }, // 4352: skeakernetsP82; (GS & XG) Shaker + { 0x4755406,0x3667601, 0x87,0x08, 0x6, +12 }, // 4353: skeakernetsP83; (GS & XG) Jingle Bells + { 0x275A346,0x3667601, 0x87,0x08, 0x6, +12 }, // 4354: skeakernetsP83; (GS & XG) Jingle Bells }; -const struct adlinsdata adlins[4495] = +const struct adlinsdata adlins[4496] = { // Amplitude begins at 1546.1, peaks 1623.1 at 0.0s, // fades to 20% at 0.0s, keyoff fades to 20% in 0.0s. @@ -9692,7 +9696,7 @@ const struct adlinsdata adlins[4495] = // Amplitude begins at 0.9, peaks 1281.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {1247,1247, 0, 0, 40000, 80,0.000000 }, // 1330: dMM109; hxMM109; musM109; raptM109; skeakernetsM109; Bag Pipe; Bag Pipe + {1247,1247, 0, 0, 40000, 80,0.000000 }, // 1330: dMM109; hxMM109; musM109; raptM109; Bag Pipe // Amplitude begins at 0.5, peaks 2984.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. @@ -21710,9 +21714,9 @@ const struct adlinsdata adlins[4495] = // fades to 20% at infs, keyoff fades to 20% in infs. {4096,4097, 0, 1, 380, 380,0.062500 }, // 4334: skeakernetsM5; Electric Piano (DX-7) - // Amplitude begins at 1431.0, peaks 1558.6 at infs, + // Amplitude begins at 1559.8, peaks 1689.4 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4098,4098, 0, 0, 1420, 1420,0.000000 }, // 4335: skeakernetsM6; Harpsichord + {4098,4098, 0, 0, 1633, 1633,0.000000 }, // 4335: skeakernetsM6; Harpsichord // Amplitude begins at 1860.8, peaks 2186.0 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. @@ -21738,9 +21742,9 @@ const struct adlinsdata adlins[4495] = // fades to 20% at infs, keyoff fades to 20% in infs. {4109,4110, 0, 1, 193, 193,0.000000 }, // 4341: skeakernetsM12; Marimba - // Amplitude begins at 2767.5, + // Amplitude begins at 2146.7, peaks 2349.0 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4111,4111, 0, 0, 46, 46,0.000000 }, // 4342: skeakernetsM13; Xylophone + {4111,4111, 0, 0, 1846, 1846,0.000000 }, // 4342: skeakernetsM13; Xylophone // Amplitude begins at 2338.5, peaks 2446.0 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. @@ -21874,9 +21878,9 @@ const struct adlinsdata adlins[4495] = // fades to 20% at infs, keyoff fades to 20% in infs. {4169,4170, 0, 1, 1813, 1813,0.031250 }, // 4375: skeakernetsM46; Orchestral Harp - // Amplitude begins at 2079.8, + // Amplitude begins at 2241.1, // fades to 20% at infs, keyoff fades to 20% in infs. - {4171,4172, 0, 1, 780, 780,0.031250 }, // 4376: skeakernetsM47; Timpani + {4171,4172, 0, 1, 1173, 1173,0.031250 }, // 4376: skeakernetsM47; Timpani // Amplitude begins at 0.6, peaks 1724.9 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. @@ -21942,9 +21946,9 @@ const struct adlinsdata adlins[4495] = // fades to 20% at infs, keyoff fades to 20% in infs. {4202,4202, 0, 0, 40000, 46,0.000000 }, // 4392: skeakernetsM64; Soprano Sax - // Amplitude begins at 0.2, peaks 1359.4 at infs, + // Amplitude begins at 0.0, peaks 1372.4 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4203,4203, 0, 0, 40000, 20,0.000000 }, // 4393: skeakernetsM65; Alto Sax + {4203,4203, 0, 0, 40000, 40,0.000000 }, // 4393: skeakernetsM65; Alto Sax // Amplitude begins at 2.5, peaks 1584.4 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. @@ -22018,89 +22022,89 @@ const struct adlinsdata adlins[4495] = // fades to 20% at infs, keyoff fades to 20% in infs. {4229,4229, 0, 0, 933, 933,0.000000 }, // 4411: skeakernetsM84; Lead 5 (charang) - // Amplitude begins at 3109.4, peaks 5378.8 at infs, - // fades to 20% at infs, keyoff fades to 20% in infs. - {1215,1216, 0, 1, 40000, 560,0.093750 }, // 4412: skeakernetsM85; Lead 6 (voice) + // Amplitude begins at 406.5, peaks 1972.6 at infs, + // fades to 20% at infs, keyoff fades to 20% in -nans. + {4230,4231, 0, 1, 40000, 0,0.156250 }, // 4412: skeakernetsM85; Lead 6 (Voice) // Amplitude begins at 12.3, peaks 2231.4 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4230,4231, 0, 1, 1660, 80,-0.046875 }, // 4413: skeakernetsM86; Lead 7 (5th sawtooth) + {4232,4233, 0, 1, 1660, 80,-0.046875 }, // 4413: skeakernetsM86; Lead 7 (5th sawtooth) // Amplitude begins at 1233.1, peaks 1298.7 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4232,4233, 0, 1, 793, 793,0.031250 }, // 4414: skeakernetsM87; Lead 8 brass + {4234,4235, 0, 1, 793, 793,0.031250 }, // 4414: skeakernetsM87; Lead 8 brass // Amplitude begins at 2625.0, peaks 4127.5 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. - {4234,4235, 0, 1, 40000, 0,0.078125 }, // 4415: skeakernetsM88; Pad 1 new age + {4236,4237, 0, 1, 40000, 0,0.078125 }, // 4415: skeakernetsM88; Pad 1 new age // Amplitude begins at 0.8, peaks 5867.8 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. - {4236,4237, 0, 1, 40000, 0,0.156250 }, // 4416: skeakernetsM89; Pad 2 (warm) + {4238,4239, 0, 1, 40000, 0,0.156250 }, // 4416: skeakernetsM89; Pad 2 (warm) // Amplitude begins at 699.2, peaks 1840.8 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4238,4239, 0, 1, 1446, 1446,0.078125 }, // 4417: skeakernetsM90; Pad 3 (polysynth) + {4240,4241, 0, 1, 1446, 1446,0.078125 }, // 4417: skeakernetsM90; Pad 3 (polysynth) // Amplitude begins at 787.1, peaks 5553.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4240,4241, 0, 1, 40000, 53,0.171875 }, // 4418: skeakernetsM91; Pad 4 (choir) + {4242,4243, 0, 1, 40000, 53,0.171875 }, // 4418: skeakernetsM91; Pad 4 (choir) // Amplitude begins at 0.9, peaks 5687.3 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4242,4243, 0, 1, 2006, 2006,0.109375 }, // 4419: skeakernetsM92; Pad 5 (bowed glass) + {4244,4245, 0, 1, 2006, 2006,0.109375 }, // 4419: skeakernetsM92; Pad 5 (bowed glass) // Amplitude begins at 0.5, peaks 3124.7 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4244,4245, 0, 1, 1166, 1166,0.062500 }, // 4420: skeakernetsM93; Pad 6 (metal) + {4246,4247, 0, 1, 1166, 1166,0.062500 }, // 4420: skeakernetsM93; Pad 6 (metal) // Amplitude begins at 0.0, peaks 2261.6 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. - {4246,4247, 0, 1, 40000, 0,0.093750 }, // 4421: skeakernetsM94; Pad 7 halo + {4248,4249, 0, 1, 40000, 0,0.093750 }, // 4421: skeakernetsM94; Pad 7 halo // Amplitude begins at 0.0, peaks 2463.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4248,4249, 0, 1, 40000, 853,0.093750 }, // 4422: skeakernetsM95; Pad 8 (sweep) + {4250,4251, 0, 1, 40000, 853,0.093750 }, // 4422: skeakernetsM95; Pad 8 (sweep) // Amplitude begins at 1593.4, peaks 1865.4 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4250,4251, 0, 1, 653, 653,0.093750 }, // 4423: skeakernetsM96; FX 1 (rain) + {4252,4253, 0, 1, 653, 653,0.093750 }, // 4423: skeakernetsM96; FX 1 (rain) // Amplitude begins at 0.8, peaks 1037.1 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. - {4252,4253, 0, 1, 40000, 0,0.062500 }, // 4424: skeakernetsM97; FX 2 soundtrack + {4254,4255, 0, 1, 40000, 0,0.062500 }, // 4424: skeakernetsM97; FX 2 soundtrack // Amplitude begins at 626.9, peaks 1813.8 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4254,4255, 0, 1, 886, 886,0.109375 }, // 4425: skeakernetsM98; FX 3 (crystal) + {4256,4257, 0, 1, 886, 886,0.109375 }, // 4425: skeakernetsM98; FX 3 (crystal) // Amplitude begins at 1227.0, peaks 1908.3 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4256,4257, 0, 1, 1653, 1653,-0.046875 }, // 4426: skeakernetsM99; FX 4 (atmosphere) + {4258,4259, 0, 1, 1653, 1653,-0.046875 }, // 4426: skeakernetsM99; FX 4 (atmosphere) // Amplitude begins at 2698.2, peaks 2784.1 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4258,4259, 0, 1, 1593, 1593,0.125000 }, // 4427: skeakernetsM100; FX 5 (brightness) + {4260,4261, 0, 1, 1593, 1593,0.125000 }, // 4427: skeakernetsM100; FX 5 (brightness) // Amplitude begins at 0.4, peaks 807.0 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. - {4260,4261, 0, 1, 40000, 0,-0.078125 }, // 4428: skeakernetsM101; FX 6 (goblin) + {4262,4263, 0, 1, 40000, 0,-0.078125 }, // 4428: skeakernetsM101; FX 6 (goblin) // Amplitude begins at 433.0, peaks 1428.1 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. - {4262,4263, 0, 1, 40000, 0,0.140625 }, // 4429: skeakernetsM102; FX 7 (echo drops) + {4264,4265, 0, 1, 40000, 0,0.140625 }, // 4429: skeakernetsM102; FX 7 (echo drops) // Amplitude begins at 8.7, peaks 939.3 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4264,4265, 0, 1, 360, 360,0.078125 }, // 4430: skeakernetsM103; * FX 8 (star-theme) + {4266,4267, 0, 1, 360, 360,0.078125 }, // 4430: skeakernetsM103; * FX 8 (star-theme) // Amplitude begins at 14.6, peaks 1251.6 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4266,4267, 0, 1, 1766, 1766,0.031250 }, // 4431: skeakernetsM104; Sitar + {4268,4269, 0, 1, 1766, 1766,0.031250 }, // 4431: skeakernetsM104; Sitar // Amplitude begins at 601.8, // fades to 20% at infs, keyoff fades to 20% in infs. - {4268,4268, 0, 0, 380, 380,0.000000 }, // 4432: skeakernetsM105; Banjo + {4270,4270, 0, 0, 380, 380,0.000000 }, // 4432: skeakernetsM105; Banjo // Amplitude begins at 1395.7, // fades to 20% at infs, keyoff fades to 20% in infs. @@ -22108,247 +22112,251 @@ const struct adlinsdata adlins[4495] = // Amplitude begins at 358.1, peaks 604.7 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4269,4269, 0, 0, 633, 633,0.000000 }, // 4434: skeakernetsM107; Koto + {4271,4271, 0, 0, 633, 633,0.000000 }, // 4434: skeakernetsM107; Koto // Amplitude begins at 2381.7, peaks 2936.3 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4270,4270, 0, 0, 173, 173,0.000000 }, // 4435: skeakernetsM108; Kalimba + {4272,4272, 0, 0, 173, 173,0.000000 }, // 4435: skeakernetsM108; Kalimba + + // Amplitude begins at 1110.8, peaks 1559.2 at infs, + // fades to 20% at infs, keyoff fades to 20% in -nans. + {4273,4274, 0, 1, 40000, 0,0.062500 }, // 4436: skeakernetsM109; Bag Pipe // Amplitude begins at 1.1, peaks 2642.3 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4271,4271, 0, 0, 40000, 66,0.000000 }, // 4436: skeakernetsM110; Fiddle + {4275,4275, 0, 0, 40000, 66,0.000000 }, // 4437: skeakernetsM110; Fiddle // Amplitude begins at 957.5, peaks 1239.4 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4272,4272, 0, 0, 40000, 33,0.000000 }, // 4437: skeakernetsM111; Shanai + {4276,4276, 0, 0, 40000, 33,0.000000 }, // 4438: skeakernetsM111; Shanai // Amplitude begins at 2706.1, peaks 3190.6 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4273,4273, 0, 0, 1940, 1940,0.000000 }, // 4438: skeakernetsM112; Tinkle Bell + {4277,4277, 0, 0, 1940, 1940,0.000000 }, // 4439: skeakernetsM112; Tinkle Bell // Amplitude begins at 464.7, peaks 2409.0 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4274,4275, 0, 1, 313, 313,0.031250 }, // 4439: skeakernetsM114; Steel Drums + {4278,4279, 0, 1, 313, 313,0.031250 }, // 4440: skeakernetsM114; Steel Drums // Amplitude begins at 2643.9, // fades to 20% at infs, keyoff fades to 20% in infs. - {4276,4276, 0, 0, 60, 60,0.000000 }, // 4440: skeakernetsM115; Woodblock + {4280,4280, 0, 0, 60, 60,0.000000 }, // 4441: skeakernetsM115; Woodblock // Amplitude begins at 2052.6, // fades to 20% at infs, keyoff fades to 20% in infs. - {4277,4278, 0, 1, 53, 53,0.000000 }, // 4441: skeakernetsM116; Taiko Drum (new) + {4281,4282, 0, 1, 53, 53,0.000000 }, // 4442: skeakernetsM116; Taiko Drum (new) // Amplitude begins at 2309.8, peaks 2481.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4279,4279, 0, 0, 140, 140,0.000000 }, // 4442: skeakernetsM117; Melodic Tom + {4283,4283, 0, 0, 140, 140,0.000000 }, // 4443: skeakernetsM117; Melodic Tom - // Amplitude begins at 2855.0, + // Amplitude begins at 2927.7, // fades to 20% at infs, keyoff fades to 20% in infs. - {4280,4281, 0, 1, 26, 26,0.000000 }, // 4443: skeakernetsM118; Synth Drum + {4284,4285, 0, 1, 26, 26,0.000000 }, // 4444: skeakernetsM118; Synth Drum // Amplitude begins at 0.0, peaks 1577.5 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4282,4283, 0, 1, 2153, 2153,0.109375 }, // 4444: skeakernetsM119; Reverse Cymbal + {4286,4287, 0, 1, 2153, 2153,0.109375 }, // 4445: skeakernetsM119; Reverse Cymbal // Amplitude begins at 0.0, peaks 1150.6 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4284,4284, 0, 0, 213, 213,0.000000 }, // 4445: skeakernetsM120; Guitar Fret Noise + {4288,4288, 0, 0, 213, 213,0.000000 }, // 4446: skeakernetsM120; Guitar Fret Noise // Amplitude begins at 0.5, peaks 1999.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4285,4286, 0, 1, 993, 26,0.000000 }, // 4446: skeakernetsM121; Breath Noise + {4289,4290, 0, 1, 993, 26,0.000000 }, // 4447: skeakernetsM121; Breath Noise // Amplitude begins at 0.0, peaks 814.7 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4287,4288, 0, 1, 5613, 5613,0.000000 }, // 4447: skeakernetsM122; Seashore + {4291,4292, 0, 1, 5613, 5613,0.000000 }, // 4448: skeakernetsM122; Seashore // Amplitude begins at 125.4, peaks 2558.8 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4289,4289, 0, 0, 220, 220,0.000000 }, // 4448: skeakernetsM123; Bird Tweet + {4293,4293, 0, 0, 220, 220,0.000000 }, // 4449: skeakernetsM123; Bird Tweet // Amplitude begins at 1177.5, peaks 1318.0 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4290,4291, 0, 1, 10306, 10306,0.000000 }, // 4449: skeakernetsM124; Telephone Ring + {4294,4295, 0, 1, 10306, 10306,0.000000 }, // 4450: skeakernetsM124; Telephone Ring // Amplitude begins at 0.0, peaks 1710.6 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4292,4293, 0, 1, 1486, 13,0.000000 }, // 4450: skeakernetsM125; Helicopter + {4296,4297, 0, 1, 1486, 13,0.000000 }, // 4451: skeakernetsM125; Helicopter // Amplitude begins at 0.0, peaks 1877.4 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. - {4294,4295, 0, 1, 40000, 0,0.000000 }, // 4451: skeakernetsM126; Applause + {4298,4299, 0, 1, 40000, 0,0.000000 }, // 4452: skeakernetsM126; Applause // Amplitude begins at 1211.7, // fades to 20% at infs, keyoff fades to 20% in infs. - {4296,4296, 0, 0, 566, 566,0.000000 }, // 4452: skeakernetsM127; Gun Shot + {4300,4300, 0, 0, 566, 566,0.000000 }, // 4453: skeakernetsM127; Gun Shot // Amplitude begins at 2239.5, // fades to 20% at infs, keyoff fades to 20% in infs. - {4297,4297, 25, 0, 33, 33,0.000000 }, // 4453: skeakernetsP35; Acoustic Bass Drum + {4301,4301, 25, 0, 33, 33,0.000000 }, // 4454: skeakernetsP35; Acoustic Bass Drum // Amplitude begins at 612.8, // fades to 20% at infs, keyoff fades to 20% in infs. - {4298,4299, 61, 1, 40, 40,0.000000 }, // 4454: skeakernetsP37; Slide Stick + {4302,4303, 61, 1, 40, 40,0.000000 }, // 4455: skeakernetsP37; Slide Stick // Amplitude begins at 263.0, peaks 989.8 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4300,4301, 37, 1, 53, 53,0.000000 }, // 4455: skeakernetsP39; ÿHand Clap + {4304,4305, 37, 1, 53, 53,0.000000 }, // 4456: skeakernetsP39; ÿHand Clap // Amplitude begins at 1309.5, peaks 1611.0 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4302,4302, 32, 0, 60, 60,0.000000 }, // 4456: skeakernetsP41; ÿLow Floor Tom + {4306,4306, 32, 0, 60, 60,0.000000 }, // 4457: skeakernetsP41; ÿLow Floor Tom // Amplitude begins at 592.6, // fades to 20% at infs, keyoff fades to 20% in infs. - {4303,4304, 48, 1, 73, 73,-1.906250 }, // 4457: skeakernetsP42; Closed High-Hat + {4307,4308, 48, 1, 73, 73,-1.906250 }, // 4458: skeakernetsP42; Closed High-Hat // Amplitude begins at 1451.5, peaks 1533.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4302,4302, 34, 0, 73, 73,0.000000 }, // 4458: skeakernetsP43; ÿHigh Floor Tom + {4306,4306, 34, 0, 73, 73,0.000000 }, // 4459: skeakernetsP43; ÿHigh Floor Tom // Amplitude begins at 33.4, peaks 538.8 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4305,4305, 48, 0, 53, 53,0.000000 }, // 4459: skeakernetsP44; Pedal High Hat + {4309,4309, 48, 0, 53, 53,0.000000 }, // 4460: skeakernetsP44; Pedal High Hat // Amplitude begins at 1643.8, // fades to 20% at infs, keyoff fades to 20% in infs. - {4306,4306, 37, 0, 46, 46,0.000000 }, // 4460: skeakernetsP45; ÿLow Tom + {4310,4310, 37, 0, 46, 46,0.000000 }, // 4461: skeakernetsP45; ÿLow Tom // Amplitude begins at 1609.9, peaks 1679.4 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4306,4306, 40, 0, 40, 40,0.000000 }, // 4461: skeakernetsP47; ÿLow-Mid Tom + {4310,4310, 40, 0, 40, 40,0.000000 }, // 4462: skeakernetsP47; ÿLow-Mid Tom // Amplitude begins at 1612.5, // fades to 20% at infs, keyoff fades to 20% in infs. - {4306,4306, 43, 0, 33, 33,0.000000 }, // 4462: skeakernetsP48; ÿHigh-Mid Tom + {4310,4310, 43, 0, 33, 33,0.000000 }, // 4463: skeakernetsP48; ÿHigh-Mid Tom // Amplitude begins at 942.8, peaks 966.9 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4307,4308, 61, 1, 1713, 1713,0.093750 }, // 4463: skeakernetsP49; Crash Cymbal 1 + {4311,4312, 61, 1, 1713, 1713,0.093750 }, // 4464: skeakernetsP49; Crash Cymbal 1 // Amplitude begins at 1497.3, // fades to 20% at infs, keyoff fades to 20% in infs. - {4306,4306, 46, 0, 60, 60,0.000000 }, // 4464: skeakernetsP50; ÿHigh Tom + {4310,4310, 46, 0, 60, 60,0.000000 }, // 4465: skeakernetsP50; ÿHigh Tom // Amplitude begins at 527.6, // fades to 20% at infs, keyoff fades to 20% in infs. - {4309,4310, 60, 1, 286, 286,0.062500 }, // 4465: skeakernetsP51; Ride Cymbal 1 + {4313,4314, 60, 1, 286, 286,0.062500 }, // 4466: skeakernetsP51; Ride Cymbal 1 // Amplitude begins at 869.9, // fades to 20% at infs, keyoff fades to 20% in infs. - {4311,4312, 79, 1, 293, 293,0.078125 }, // 4466: skeakernetsP52; Chinses Cymbal + {4315,4316, 79, 1, 293, 293,0.078125 }, // 4467: skeakernetsP52; Chinses Cymbal // Amplitude begins at 645.3, peaks 666.8 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4313,4313, 62, 0, 1726, 1726,0.000000 }, // 4467: skeakernetsP53; Ride Bell + {4317,4317, 62, 0, 1726, 1726,0.000000 }, // 4468: skeakernetsP53; Ride Bell // Amplitude begins at 844.2, peaks 1100.9 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4314,4315, 80, 1, 106, 106,0.125000 }, // 4468: skeakernetsP54; Tambourine + {4318,4319, 80, 1, 106, 106,0.125000 }, // 4469: skeakernetsP54; Tambourine // Amplitude begins at 795.8, // fades to 20% at infs, keyoff fades to 20% in infs. - {4316,4317, 67, 1, 240, 240,0.078125 }, // 4469: skeakernetsP55; Splash Cymbal + {4320,4321, 67, 1, 240, 240,0.078125 }, // 4470: skeakernetsP55; Splash Cymbal // Amplitude begins at 2425.9, // fades to 20% at infs, keyoff fades to 20% in infs. - {4318,4318, 58, 0, 73, 73,0.000000 }, // 4470: skeakernetsP56; Cowbell + {4322,4322, 58, 0, 73, 73,0.000000 }, // 4471: skeakernetsP56; Cowbell // Amplitude begins at 1409.0, peaks 1532.8 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4319,4320, 62, 1, 1946, 1946,0.093750 }, // 4471: skeakernetsP57; Crash Cymbal 2 + {4323,4324, 62, 1, 1946, 1946,0.093750 }, // 4472: skeakernetsP57; Crash Cymbal 2 // Amplitude begins at 2144.7, peaks 2521.0 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4321,4321, 24, 0, 780, 780,0.000000 }, // 4472: skeakernetsP58; Vibraslap + {4325,4325, 24, 0, 780, 780,0.000000 }, // 4473: skeakernetsP58; Vibraslap // Amplitude begins at 1280.9, peaks 1290.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4322,4322, 61, 0, 206, 206,0.000000 }, // 4473: skeakernetsP59; Ride Cymbal 2 + {4326,4326, 61, 0, 206, 206,0.000000 }, // 4474: skeakernetsP59; Ride Cymbal 2 // Amplitude begins at 579.3, peaks 2735.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4323,4324, 41, 1, 100, 100,0.000000 }, // 4474: skeakernetsP60; High Bongo (New) + {4327,4328, 41, 1, 100, 100,0.000000 }, // 4475: skeakernetsP60; High Bongo (New) // Amplitude begins at 712.1, peaks 2862.8 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4325,4326, 35, 1, 160, 160,0.000000 }, // 4475: skeakernetsP61; Low Bongo (New) + {4329,4330, 35, 1, 160, 160,0.000000 }, // 4476: skeakernetsP61; Low Bongo (New) // Amplitude begins at 281.8, peaks 1597.9 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4327,4328, 29, 1, 40, 40,0.000000 }, // 4476: skeakernetsP62; Mute high conga (New) + {4331,4332, 29, 1, 40, 40,0.000000 }, // 4477: skeakernetsP62; Mute high conga (New) // Amplitude begins at 846.9, peaks 2855.8 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4329,4330, 41, 1, 166, 166,0.000000 }, // 4477: skeakernetsP63; Open High Conga (New) + {4333,4334, 41, 1, 166, 166,0.000000 }, // 4478: skeakernetsP63; Open High Conga (New) // Amplitude begins at 915.5, peaks 2837.2 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4329,4330, 37, 1, 160, 160,0.000000 }, // 4478: skeakernetsP64; Low Conga (New) + {4333,4334, 37, 1, 160, 160,0.000000 }, // 4479: skeakernetsP64; Low Conga (New) // Amplitude begins at 2674.8, // fades to 20% at infs, keyoff fades to 20% in infs. - {4331,4331, 55, 0, 66, 66,0.000000 }, // 4479: skeakernetsP65; High Timbale + {4335,4335, 55, 0, 66, 66,0.000000 }, // 4480: skeakernetsP65; High Timbale // Amplitude begins at 2756.4, // fades to 20% at infs, keyoff fades to 20% in infs. - {4331,4331, 48, 0, 80, 80,0.000000 }, // 4480: skeakernetsP66; Low Timbale + {4335,4335, 48, 0, 80, 80,0.000000 }, // 4481: skeakernetsP66; Low Timbale // Amplitude begins at 1471.3, // fades to 20% at infs, keyoff fades to 20% in infs. - {4332,4333, 78, 1, 126, 126,0.000000 }, // 4481: skeakernetsP67; High Agogo + {4336,4337, 78, 1, 126, 126,0.000000 }, // 4482: skeakernetsP67; High Agogo // Amplitude begins at 1721.1, // fades to 20% at infs, keyoff fades to 20% in infs. - {4332,4334, 73, 1, 113, 113,0.000000 }, // 4482: skeakernetsP68; Low Agogo + {4336,4338, 73, 1, 113, 113,0.000000 }, // 4483: skeakernetsP68; Low Agogo // Amplitude begins at 42.0, peaks 443.4 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4335,4335, 40, 0, 140, 140,0.000000 }, // 4483: skeakernetsP70; Maracas + {4339,4339, 40, 0, 140, 140,0.000000 }, // 4484: skeakernetsP70; Maracas // Amplitude begins at 1203.0, peaks 1485.9 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4336,4336, 45, 0, 313, 313,0.000000 }, // 4484: skeakernetsP71; Short Whistle + {4340,4340, 45, 0, 313, 313,0.000000 }, // 4485: skeakernetsP71; Short Whistle // Amplitude begins at 1200.3, peaks 1494.7 at infs, // fades to 20% at infs, keyoff fades to 20% in -nans. - {4337,4337, 42, 0, 40000, 0,0.000000 }, // 4485: skeakernetsP72; Long Whistle + {4341,4341, 42, 0, 40000, 0,0.000000 }, // 4486: skeakernetsP72; Long Whistle // Amplitude begins at 1813.9, // fades to 20% at infs, keyoff fades to 20% in infs. - {4338,4339, 48, 1, 80, 80,0.000000 }, // 4486: skeakernetsP73; ÿShort Guiro + {4342,4343, 48, 1, 80, 80,0.000000 }, // 4487: skeakernetsP73; ÿShort Guiro // Amplitude begins at 2421.1, // fades to 20% at infs, keyoff fades to 20% in infs. - {4340,4341, 48, 1, 53, 53,0.000000 }, // 4487: skeakernetsP74; ÿLong Guiro + {4344,4345, 48, 1, 53, 53,0.000000 }, // 4488: skeakernetsP74; ÿLong Guiro // Amplitude begins at 2419.2, // fades to 20% at infs, keyoff fades to 20% in infs. - {4342,4342, 73, 0, 60, 60,0.000000 }, // 4488: skeakernetsP75; Claves + {4346,4346, 73, 0, 60, 60,0.000000 }, // 4489: skeakernetsP75; Claves // Amplitude begins at 2067.1, // fades to 20% at infs, keyoff fades to 20% in infs. - {4343,4343, 16, 0, 20, 20,0.000000 }, // 4489: skeakernetsP78; Mute Cuica + {4347,4347, 16, 0, 20, 20,0.000000 }, // 4490: skeakernetsP78; Mute Cuica // Amplitude begins at 2547.6, // fades to 20% at infs, keyoff fades to 20% in infs. - {4344,4344, 16, 0, 146, 146,0.000000 }, // 4490: skeakernetsP79; Open Cuica + {4348,4348, 16, 0, 146, 146,0.000000 }, // 4491: skeakernetsP79; Open Cuica // Amplitude begins at 780.7, // fades to 20% at infs, keyoff fades to 20% in infs. - {4345,4345, 90, 0, 80, 80,0.000000 }, // 4491: skeakernetsP80; Mute Triangle + {4349,4349, 90, 0, 80, 80,0.000000 }, // 4492: skeakernetsP80; Mute Triangle // Amplitude begins at 823.4, // fades to 20% at infs, keyoff fades to 20% in infs. - {4346,4346, 90, 0, 306, 306,0.000000 }, // 4492: skeakernetsP81; Open Triangle + {4350,4350, 90, 0, 306, 306,0.000000 }, // 4493: skeakernetsP81; Open Triangle // Amplitude begins at 5.1, peaks 649.7 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4347,4348, 64, 1, 233, 233,0.031250 }, // 4493: skeakernetsP82; (GS & XG) Shaker + {4351,4352, 64, 1, 233, 233,0.031250 }, // 4494: skeakernetsP82; (GS & XG) Shaker // Amplitude begins at 15.2, peaks 820.6 at infs, // fades to 20% at infs, keyoff fades to 20% in infs. - {4349,4350, 80, 1, 140, 140,0.031250 }, // 4494: skeakernetsP83; (GS & XG) Jingle Bells + {4353,4354, 80, 1, 140, 140,0.031250 }, // 4495: skeakernetsP83; (GS & XG) Jingle Bells }; @@ -23744,14 +23752,14 @@ const unsigned short banks[73][256] = 4377,4378,4379,4380,4381,4382,4383,4384,4385,4386, 57,4387,4388,4389,4390,4391, 4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,1300,4406, 4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422, -4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,1330,4436,4437, -4438,1334,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452, +4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438, +4439,1334,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, - 806, 806, 806,4453,1349,4454,4218,4455,4219,4456,4457,4458,4459,4460,4222,4461, -4462,4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477, -4478,4479,4480,4481,4482, 320,4483,4484,4485,4486,4487,4488,1373,1374,4489,4490, -4491,4492,4493,4494, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, + 806, 806, 806,4454,1349,4455,4218,4456,4219,4457,4458,4459,4460,4461,4222,4462, +4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478, +4479,4480,4481,4482,4483, 320,4484,4485,4486,4487,4488,4489,1373,1374,4490,4491, +4492,4493,4494,4495, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, 806, }, diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index 4710dfe..7aa9e8b 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -31,36 +31,11 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate) { ADL_MIDIPlayer *midi_device; midi_device = (ADL_MIDIPlayer *)malloc(sizeof(ADL_MIDIPlayer)); - midi_device->PCM_RATE = static_cast<unsigned long>(sample_rate); - midi_device->AdlBank = 0; - midi_device->NumFourOps = 7; - midi_device->NumCards = 2; - midi_device->HighTremoloMode = 0; - midi_device->HighVibratoMode = 0; - midi_device->AdlPercussionMode = 0; - midi_device->LogarithmicVolumes = 0; - midi_device->SkipForward = 0; - midi_device->loopingIsEnabled = 0; - midi_device->ScaleModulators = 0; - midi_device->delay = 0.0; - midi_device->carry = 0.0; - midi_device->mindelay = 1.0 / (double)midi_device->PCM_RATE; - midi_device->maxdelay = 512.0 / (double)midi_device->PCM_RATE; - midi_device->stored_samples = 0; - midi_device->backup_samples_size = 0; - MIDIplay *player = new MIDIplay; midi_device->adl_midiPlayer = player; - player->config = midi_device; - player->opl._parent = midi_device; - player->opl.NumCards = midi_device->NumCards; - player->opl.AdlBank = midi_device->AdlBank; - player->opl.NumFourOps = midi_device->NumFourOps; - player->opl.LogarithmicVolumes = (midi_device->LogarithmicVolumes != 0); - player->opl.HighTremoloMode = (midi_device->HighTremoloMode != 0); - player->opl.HighVibratoMode = (midi_device->HighVibratoMode != 0); - player->opl.AdlPercussionMode = (midi_device->AdlPercussionMode != 0); - player->opl.ScaleModulators = (midi_device->ScaleModulators != 0); + player->m_setup.PCM_RATE = static_cast<unsigned long>(sample_rate); + player->m_setup.mindelay = 1.0 / (double)player->m_setup.PCM_RATE; + player->m_setup.maxdelay = 512.0 / (double)player->m_setup.PCM_RATE; player->ChooseDevice("none"); adlRefreshNumCards(midi_device); return midi_device; @@ -71,10 +46,9 @@ ADLMIDI_EXPORT int adl_setNumCards(ADL_MIDIPlayer *device, int numCards) if(device == NULL) return -2; - device->NumCards = static_cast<unsigned int>(numCards); - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.NumCards = device->NumCards; - - if(device->NumCards < 1 || device->NumCards > MaxCards) + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.NumCards = static_cast<unsigned int>(numCards); + if(play->m_setup.NumCards < 1 || play->m_setup.NumCards > MaxCards) { std::stringstream s; s << "number of cards may only be 1.." << MaxCards << ".\n"; @@ -82,6 +56,8 @@ ADLMIDI_EXPORT int adl_setNumCards(ADL_MIDIPlayer *device, int numCards) return -1; } + play->opl.NumCards = play->m_setup.NumCards; + return adlRefreshNumCards(device); } @@ -99,11 +75,11 @@ ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) if(bankno < 0) bankno = 0; - device->AdlBank = static_cast<uint32_t>(bankno); MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); - play->opl.AdlBank = device->AdlBank; + play->m_setup.AdlBank = static_cast<uint32_t>(bankno); + play->opl.AdlBank = play->m_setup.AdlBank; - if(device->AdlBank >= NumBanks) + if(play->m_setup.AdlBank >= NumBanks) { std::stringstream s; s << "bank number may only be 0.." << (NumBanks - 1) << ".\n"; @@ -127,13 +103,16 @@ ADLMIDI_EXPORT const char *const *adl_getBankNames() ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4) { - device->NumFourOps = static_cast<unsigned int>(ops4); - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.NumFourOps = device->NumFourOps; + if(!device) + return -1; + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.NumFourOps = static_cast<unsigned int>(ops4); + play->opl.NumFourOps = play->m_setup.NumFourOps; - if(device->NumFourOps > 6 * device->NumCards) + if(play->m_setup.NumFourOps > 6 * play->m_setup.NumCards) { std::stringstream s; - s << "number of four-op channels may only be 0.." << (6 * (device->NumCards)) << " when " << device->NumCards << " OPL3 cards are used.\n"; + s << "number of four-op channels may only be 0.." << (6 * (play->m_setup.NumCards)) << " when " << play->m_setup.NumCards << " OPL3 cards are used.\n"; ADLMIDI_ErrorString = s.str(); return -1; } @@ -145,55 +124,56 @@ ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4) ADLMIDI_EXPORT void adl_setPercMode(ADL_MIDIPlayer *device, int percmod) { if(!device) return; - - device->AdlPercussionMode = static_cast<unsigned int>(percmod); - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.AdlPercussionMode = (device->AdlPercussionMode != 0); + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.AdlPercussionMode = (percmod != 0); + play->opl.AdlPercussionMode = play->m_setup.AdlPercussionMode; } ADLMIDI_EXPORT void adl_setHVibrato(ADL_MIDIPlayer *device, int hvibro) { if(!device) return; - - device->HighVibratoMode = static_cast<unsigned int>(hvibro); - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.HighVibratoMode = (device->HighVibratoMode != 0); + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.HighVibratoMode = (hvibro != 0); + play->opl.HighVibratoMode = play->m_setup.HighVibratoMode; } ADLMIDI_EXPORT void adl_setHTremolo(ADL_MIDIPlayer *device, int htremo) { if(!device) return; - - device->HighTremoloMode = static_cast<unsigned int>(htremo); - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.HighTremoloMode = (device->HighTremoloMode != 0); + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.HighTremoloMode = (htremo != 0); + play->opl.HighTremoloMode = play->m_setup.HighTremoloMode; } ADLMIDI_EXPORT void adl_setScaleModulators(ADL_MIDIPlayer *device, int smod) { if(!device) return; - - device->ScaleModulators = static_cast<unsigned int>(smod); - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.ScaleModulators = (device->ScaleModulators != 0); + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.ScaleModulators = (smod != 0); + play->opl.ScaleModulators = play->m_setup.ScaleModulators; } ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn) { if(!device) return; - device->loopingIsEnabled = (loopEn != 0); + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.loopingIsEnabled = (loopEn != 0); } ADLMIDI_EXPORT void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol) { if(!device) return; - - device->LogarithmicVolumes = static_cast<unsigned int>(logvol); - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.LogarithmicVolumes = (device->LogarithmicVolumes != 0); + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.LogarithmicVolumes = (logvol != 0); + play->opl.LogarithmicVolumes = play->m_setup.LogarithmicVolumes; } ADLMIDI_EXPORT void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel) { if(!device) return; - - device->VolumeModel = volumeModel; - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(volumeModel)); + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.VolumeModel = volumeModel; + play->opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(volumeModel)); } ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, char *filePath) @@ -202,10 +182,10 @@ ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, char *filePat if(device && device->adl_midiPlayer) { - device->stored_samples = 0; - device->backup_samples_size = 0; - - if(!reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->LoadBank(filePath)) + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.stored_samples = 0; + play->m_setup.backup_samples_size = 0; + if(!play->LoadBank(filePath)) { if(ADLMIDI_ErrorString.empty()) ADLMIDI_ErrorString = "ADL MIDI: Can't load file"; @@ -224,10 +204,10 @@ ADLMIDI_EXPORT int adl_openBankData(struct ADL_MIDIPlayer *device, void *mem, lo if(device && device->adl_midiPlayer) { - device->stored_samples = 0; - device->backup_samples_size = 0; - - if(!reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->LoadBank(mem, static_cast<size_t>(size))) + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.stored_samples = 0; + play->m_setup.backup_samples_size = 0; + if(!play->LoadBank(mem, static_cast<size_t>(size))) { if(ADLMIDI_ErrorString.empty()) ADLMIDI_ErrorString = "ADL MIDI: Can't load data from memory"; @@ -246,14 +226,13 @@ ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, char *filePath) if(device && device->adl_midiPlayer) { - device->stored_samples = 0; - device->backup_samples_size = 0; - - if(!reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->LoadMIDI(filePath)) + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.stored_samples = 0; + play->m_setup.backup_samples_size = 0; + if(!play->LoadMIDI(filePath)) { if(ADLMIDI_ErrorString.empty()) ADLMIDI_ErrorString = "ADL MIDI: Can't load file"; - return -1; } else return 0; @@ -269,14 +248,13 @@ ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, void *mem, long size) if(device && device->adl_midiPlayer) { - device->stored_samples = 0; - device->backup_samples_size = 0; - - if(!reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->LoadMIDI(mem, static_cast<size_t>(size))) + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.stored_samples = 0; + play->m_setup.backup_samples_size = 0; + if(!play->LoadMIDI(mem, static_cast<size_t>(size))) { if(ADLMIDI_ErrorString.empty()) ADLMIDI_ErrorString = "ADL MIDI: Can't load data from memory"; - return -1; } else return 0; @@ -294,8 +272,8 @@ ADLMIDI_EXPORT const char *adl_errorString() ADLMIDI_EXPORT const char *adl_getMusicTitle(ADL_MIDIPlayer *device) { - if(!device) return ""; - + if(!device) + return ""; return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->musTitle.c_str(); } @@ -303,7 +281,6 @@ ADLMIDI_EXPORT void adl_close(ADL_MIDIPlayer *device) { if(device->adl_midiPlayer) delete reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); - device->adl_midiPlayer = NULL; free(device); device = NULL; @@ -313,10 +290,45 @@ ADLMIDI_EXPORT void adl_reset(ADL_MIDIPlayer *device) { if(!device) return; + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + play->m_setup.stored_samples = 0; + play->m_setup.backup_samples_size = 0; + play->opl.Reset(play->m_setup.PCM_RATE); +} + +ADLMIDI_EXPORT double adl_totalTimeLength(ADL_MIDIPlayer *device) +{ + if(!device) + return -1.0; + return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->timeLength(); +} + +ADLMIDI_EXPORT double adl_loopStartTime(struct ADL_MIDIPlayer *device) +{ + if(!device) + return -1.0; + return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->getLoopStart(); +} + +ADLMIDI_EXPORT double adl_loopEndTime(struct ADL_MIDIPlayer *device) +{ + if(!device) + return -1.0; + return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->getLoopEnd(); +} - device->stored_samples = 0; - device->backup_samples_size = 0; - reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->opl.Reset(); +ADLMIDI_EXPORT double adl_positionTell(struct ADL_MIDIPlayer *device) +{ + if(!device) + return -1.0; + return reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->tell(); +} + +ADLMIDI_EXPORT void adl_positionSeek(struct ADL_MIDIPlayer *device, double seconds) +{ + if(!device) + return; + reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->seek(seconds); } ADLMIDI_EXPORT void adl_positionRewind(struct ADL_MIDIPlayer *device) @@ -326,8 +338,15 @@ ADLMIDI_EXPORT void adl_positionRewind(struct ADL_MIDIPlayer *device) reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->rewind(); } +ADLMIDI_EXPORT void adl_setTempo(struct ADL_MIDIPlayer *device, double tempo) +{ + if(!device || (tempo <= 0.0)) + return; + reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->setTempo(tempo); +} + -inline static void SendStereoAudio(ADL_MIDIPlayer *device, +inline static void SendStereoAudio(MIDIplay::Setup &device, int &samples_requested, ssize_t &in_size, short *_in, @@ -337,7 +356,7 @@ inline static void SendStereoAudio(ADL_MIDIPlayer *device, if(!in_size) return; - device->stored_samples = 0; + device.stored_samples = 0; size_t offset = static_cast<size_t>(out_pos); size_t inSamples = static_cast<size_t>(in_size * 2); size_t maxSamples = static_cast<size_t>(samples_requested) - offset; @@ -347,10 +366,10 @@ inline static void SendStereoAudio(ADL_MIDIPlayer *device, if(maxSamples < inSamples) { size_t appendSize = inSamples - maxSamples; - std::memcpy(device->backup_samples + device->backup_samples_size, + std::memcpy(device.backup_samples + device.backup_samples_size, maxSamples + _in, appendSize * sizeof(short)); - device->backup_samples_size += (ssize_t)appendSize; - device->stored_samples += (ssize_t)appendSize; + device.backup_samples_size += (ssize_t)appendSize; + device.stored_samples += (ssize_t)appendSize; } } @@ -360,6 +379,9 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out) if(!device) return 0; + MIDIplay *player = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + MIDIplay::Setup &setup = player->m_setup; + sampleCount -= sampleCount % 2; //Avoid even sample requests if(sampleCount < 0) @@ -372,44 +394,42 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out) while(left > 0) { - if(device->backup_samples_size > 0) + if(setup.backup_samples_size > 0) { //Send reserved samples if exist ssize_t ate = 0; - while((ate < device->backup_samples_size) && (ate < left)) + while((ate < setup.backup_samples_size) && (ate < left)) { - out[ate] = device->backup_samples[ate]; + out[ate] = setup.backup_samples[ate]; ate++; } left -= (int)ate; gotten_len += ate; - if(ate < device->backup_samples_size) + if(ate < setup.backup_samples_size) { for(ssize_t j = 0; j < ate; j++) - device->backup_samples[(ate - 1) - j] = device->backup_samples[(device->backup_samples_size - 1) - j]; + setup.backup_samples[(ate - 1) - j] = setup.backup_samples[(setup.backup_samples_size - 1) - j]; } - device->backup_samples_size -= ate; + setup.backup_samples_size -= ate; } else { - const double eat_delay = device->delay < device->maxdelay ? device->delay : device->maxdelay; - device->delay -= eat_delay; - device->carry += device->PCM_RATE * eat_delay; - n_periodCountStereo = static_cast<ssize_t>(device->carry); - device->carry -= n_periodCountStereo; - - if(device->SkipForward > 0) - device->SkipForward -= 1; + const double eat_delay = setup.delay < setup.maxdelay ? setup.delay : setup.maxdelay; + setup.delay -= eat_delay; + setup.carry += setup.PCM_RATE * eat_delay; + n_periodCountStereo = static_cast<ssize_t>(setup.carry); + setup.carry -= n_periodCountStereo; + + if(setup.SkipForward > 0) + setup.SkipForward -= 1; else { - MIDIplay *player = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); - - if((player->atEnd) && (device->delay <= 0.0)) - break;//Stop to fetch samples at reaching of song end with disabled loop + if((player->atEnd) && (setup.delay <= 0.0)) + break;//Stop to fetch samples at reaching the song end with disabled loop //! Count of stereo samples ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo; @@ -420,7 +440,7 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out) int16_t *out_buf = player->outBuf; std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(int16_t)); - if(device->NumCards == 1) + if(player->m_setup.NumCards == 1) { #ifdef ADLMIDI_USE_DOSBOX_OPL player->opl.cards[0].GenerateArr(out_buf, &in_generatedStereo); @@ -428,13 +448,11 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out) #else OPL3_GenerateStream(&player->opl.cards[0], out_buf, static_cast<Bit32u>(in_generatedStereo)); #endif - /* Process it */ - SendStereoAudio(device, sampleCount, in_generatedStereo, out_buf, gotten_len, out); } else if(n_periodCountStereo > 0) { /* Generate data from every chip and mix result */ - for(unsigned card = 0; card < device->NumCards; ++card) + for(unsigned card = 0; card < player->m_setup.NumCards; ++card) { #ifdef ADLMIDI_USE_DOSBOX_OPL player->opl.cards[card].GenerateArrMix(out_buf, &in_generatedStereo); @@ -443,16 +461,15 @@ ADLMIDI_EXPORT int adl_play(ADL_MIDIPlayer *device, int sampleCount, short *out) OPL3_GenerateStreamMix(&player->opl.cards[card], out_buf, static_cast<Bit32u>(in_generatedStereo)); #endif } - - /* Process it */ - SendStereoAudio(device, sampleCount, in_generatedStereo, out_buf, gotten_len, out); } + /* Process it */ + SendStereoAudio(setup, sampleCount, in_generatedStereo, out_buf, gotten_len, out); left -= (int)in_generatedPhys; - gotten_len += (in_generatedPhys) - device->stored_samples; + gotten_len += (in_generatedPhys) - setup.stored_samples; } - device->delay = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer)->Tick(eat_delay, device->mindelay); + setup.delay = player->Tick(eat_delay, setup.mindelay); } } diff --git a/src/adlmidi_load.cpp b/src/adlmidi_load.cpp index 9ec14e7..08892a5 100644 --- a/src/adlmidi_load.cpp +++ b/src/adlmidi_load.cpp @@ -48,34 +48,6 @@ uint64_t MIDIplay::ReadLEint(const void *buffer, size_t nbytes) return result; } -uint64_t MIDIplay::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; -} - bool MIDIplay::LoadBank(const std::string &filename) { fileReader file; @@ -122,7 +94,7 @@ enum WOPL_InstrumentFlags { WOPL_Flags_NONE = 0, WOPL_Flag_Enable4OP = 0x01, - WOPL_Flag_Pseudo4OP = 0x02, + WOPL_Flag_Pseudo4OP = 0x02 }; struct WOPL_Inst @@ -295,7 +267,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) } } - opl.AdlBank = opl._parent->AdlBank; + opl.AdlBank = m_setup.AdlBank; opl.dynamic_metainstruments.clear(); opl.dynamic_instruments.clear(); @@ -369,6 +341,7 @@ bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr) ADL_UNUSED(fsize); //! Temp buffer for conversion AdlMIDI_CPtr<uint8_t> cvt_buf; + errorString.clear(); #ifdef DISABLE_EMBEDDED_BANKS if((opl.AdlBank != ~0u) || (opl.dynamic_metainstruments.size() < 256)) @@ -389,18 +362,18 @@ bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr) /**** Set all properties BEFORE starting of actial file reading! ****/ - config->stored_samples = 0; - config->backup_samples_size = 0; - opl.AdlPercussionMode = (config->AdlPercussionMode != 0); - opl.HighTremoloMode = (config->HighTremoloMode != 0); - opl.HighVibratoMode = (config->HighVibratoMode != 0); - opl.ScaleModulators = (config->ScaleModulators != 0); - opl.LogarithmicVolumes = (config->LogarithmicVolumes != 0); - opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(config->VolumeModel)); + m_setup.stored_samples = 0; + m_setup.backup_samples_size = 0; + opl.AdlPercussionMode = m_setup.AdlPercussionMode; + opl.HighTremoloMode = m_setup.HighTremoloMode; + opl.HighVibratoMode = m_setup.HighVibratoMode; + opl.ScaleModulators = m_setup.ScaleModulators; + opl.LogarithmicVolumes = m_setup.LogarithmicVolumes; + opl.ChangeVolumeRangesModel(static_cast<ADLMIDI_VolumeModels>(m_setup.VolumeModel)); - if(config->VolumeModel == ADLMIDI_VolumeModel_AUTO) + if(m_setup.VolumeModel == ADLMIDI_VolumeModel_AUTO) { - switch(config->AdlBank) + switch(m_setup.AdlBank) { default: opl.m_volumeScale = OPL3::VOLUME_Generic; @@ -429,17 +402,15 @@ bool MIDIplay::LoadMIDI(MIDIplay::fileReader &fr) } } - opl.NumCards = config->NumCards; - opl.NumFourOps = config->NumFourOps; + opl.NumCards = m_setup.NumCards; + opl.NumFourOps = m_setup.NumFourOps; cmf_percussion_mode = false; - opl.Reset(); + opl.Reset(m_setup.PCM_RATE); trackStart = true; atEnd = false; loopStart = true; - loopStart_passed = false; invalidLoop = false; - loopStart_hit = false; bool is_GMF = false; // GMD/MUS files (ScummVM) //bool is_MUS = false; // MUS/DMX files (Doom) @@ -655,8 +626,8 @@ InvFmt: TrackData.clear(); TrackData.resize(TrackCount, std::vector<uint8_t>()); - CurrentPosition.track.clear(); - CurrentPosition.track.resize(TrackCount); + //CurrentPosition.track.clear(); + //CurrentPosition.track.resize(TrackCount); InvDeltaTicks = fraction<uint64_t>(1, 1000000l * static_cast<uint64_t>(DeltaTicks)); //Tempo = 1000000l * InvDeltaTicks; Tempo = fraction<uint64_t>(1, static_cast<uint64_t>(DeltaTicks)); @@ -673,7 +644,8 @@ InvFmt: //std::fprintf(stderr, "Reading IMF file...\n"); size_t end = static_cast<uint8_t>(HeaderBuf[0]) + 256 * static_cast<uint8_t>(HeaderBuf[1]); unsigned IMF_tempo = 1428; - static const unsigned char imf_tempo[] = {0xFF, 0x51, 0x4, + static const unsigned char imf_tempo[] = {0x0,//Zero delay! + MidiEvent::T_SPECIAL, MidiEvent::ST_TEMPOCHANGE, 0x4, static_cast<uint8_t>(IMF_tempo >> 24), static_cast<uint8_t>(IMF_tempo >> 16), static_cast<uint8_t>(IMF_tempo >> 8), @@ -686,31 +658,31 @@ InvFmt: while(fr.tell() < end && !fr.eof()) { uint8_t special_event_buf[5]; - special_event_buf[0] = 0xFF; - special_event_buf[1] = 0xE3; + uint8_t raw[4]; + special_event_buf[0] = MidiEvent::T_SPECIAL; + special_event_buf[1] = MidiEvent::ST_RAWOPL; special_event_buf[2] = 0x02; - special_event_buf[3] = static_cast<uint8_t>(fr.getc()); // port index - special_event_buf[4] = static_cast<uint8_t>(fr.getc()); // port value - uint32_t delay = static_cast<uint16_t>(fr.getc()); - delay += 256 * static_cast<uint16_t>(fr.getc()); + 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<uint32_t>(raw[2]); + delay += 256 * static_cast<uint32_t>(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; + //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! } @@ -734,10 +706,8 @@ InvFmt: else { fsize = fr.read(HeaderBuf, 1, 8); - if(std::memcmp(HeaderBuf, "MTrk", 4) != 0) goto InvFmt; - TrackLength = (size_t)ReadBEint(HeaderBuf + 4, 4); } @@ -749,19 +719,18 @@ InvFmt: if(is_GMF /*|| is_MUS*/) // Note: CMF does include the track end tag. TrackData[tk].insert(TrackData[tk].end(), EndTag + 0, EndTag + 4); - 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; - } + //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; + //} } } @@ -774,10 +743,14 @@ InvFmt: return false; } - //Build new MIDI events table (WIP!!!) - buildTrackData(); + //Build new MIDI events table (ALPHA!!!) + if(!buildTrackData()) + { + ADLMIDI_ErrorString = fr._fileName + ": MIDI data parsing error has occouped!\n" + errorString; + return false; + } - opl.Reset(); // Reset AdLib + opl.Reset(m_setup.PCM_RATE); // Reset AdLib //opl.Reset(); // ...twice (just in case someone misprogrammed OPL3 previously) ch.clear(); ch.resize(opl.NumChannels); diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index f536f4e..577e8b8 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -23,7 +23,6 @@ #include "adlmidi_private.hpp" - // Mapping from MIDI volume level to OPL level value. static const uint32_t DMX_volume_mapping_table[] = @@ -132,27 +131,29 @@ void MIDIplay::AdlChannel::AddAge(int64_t ms) MIDIplay::MidiEvent::MidiEvent() : type(T_UNKNOWN), subtype(T_UNKNOWN), - channel(0) + channel(0), + isValid(1), + absPosition(0) {} -MIDIplay::MidiTrackPos::MidiTrackPos() : +MIDIplay::MidiTrackRow::MidiTrackRow() : time(0.0), delay(0), - timeDelay(0.0), - next(NULL) + absPos(0), + timeDelay(0.0) {} -void MIDIplay::MidiTrackPos::reset() +void MIDIplay::MidiTrackRow::reset() { time = 0.0; delay = 0; + absPos = 0; timeDelay = 0.0; events.clear(); - next = NULL; } -void MIDIplay::MidiTrackPos::sortEvents() +void MIDIplay::MidiTrackRow::sortEvents() { std::vector<MidiEvent> metas; std::vector<MidiEvent> noteOffs; @@ -172,7 +173,7 @@ void MIDIplay::MidiTrackPos::sortEvents() controllers.push_back(events[i]); } else - if((events[i].type == MidiEvent::T_SPECIAL) && (events[i].subtype == MidiEvent::ST_META)) + if((events[i].type == MidiEvent::T_SPECIAL) && (events[i].subtype == MidiEvent::ST_MARKER)) metas.push_back(events[i]); else anyOther.push_back(events[i]); @@ -185,83 +186,316 @@ void MIDIplay::MidiTrackPos::sortEvents() events.insert(events.end(), anyOther.begin(), anyOther.end()); } -void MIDIplay::buildTrackData() +bool MIDIplay::buildTrackData() { + fullSongTimeLength = 0.0; + loopStartTime = -1.0; + loopEndTime = -1.0; + musTitle.clear(); trackDataNew.clear(); - trackDataNewStatus.clear(); const size_t trackCount = TrackData.size(); - trackDataNew.resize(trackCount, std::vector<MidiTrackPos>()); - trackDataNewStatus.resize(trackCount, 0); + 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); - /* TODO: Based on tempo changes, make accurate seconds time marking. - * Current way is inaccurate, because of tempo change at different track - * will cause time desynchronization between tracks. - * Also, seconds calculation is incorrect */ + //Tempo change events + std::vector<MidiEvent> 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!) + */ for(size_t tk = 0; tk < trackCount; ++tk) { - fraction<uint64_t> currentTempo = Tempo; - double time = 0.0; + uint64_t abs_position = 0; int status = 0; - std::vector<MidiTrackPos> posEvents; MidiEvent event; + bool ok = false; + uint8_t *end = TrackData[tk].data() + TrackData[tk].size(); uint8_t *trackPtr = TrackData[tk].data(); //Time delay that follows the first event in the track { - MidiTrackPos evtPos; - evtPos.delay = ReadVarLen(&trackPtr); - fraction<uint64_t> t = evtPos.delay * currentTempo; + MidiTrackRow evtPos; + evtPos.delay = ReadVarLenEx(&trackPtr, end, ok); + if(!ok) + { + int len = std::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; + } CurrentPositionNew.wait = evtPos.delay; - evtPos.timeDelay = t.value(); - time += evtPos.timeDelay; + evtPos.absPos = abs_position; + abs_position += evtPos.delay; trackDataNew[tk].push_back(evtPos); } - MidiTrackPos evtPos; + MidiTrackRow evtPos; do { - event = parseEvent(&trackPtr, status); + event = parseEvent(&trackPtr, end, status); + if(!event.isValid) + { + int len = std::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 && event.subtype == MidiEvent::ST_TEMPOCHANGE) - currentTempo = InvDeltaTicks * fraction<uint64_t>(ReadBEint(event.data.data(), event.data.size())); - evtPos.delay = ReadVarLen(&trackPtr); + 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) + { + int len = std::snprintf(error, 150, "buildTrackData: Can't read variable-length value in the track %d.\n", (int)tk); + if((len > 0) && (len < 150)) + errorString += std::string(error, (size_t)len); + return false; + } + } + if((evtPos.delay > 0) || (event.subtype == MidiEvent::ST_ENDTRACK)) { - fraction<uint64_t> t = evtPos.delay * currentTempo; - evtPos.timeDelay = t.value() ; - evtPos.time = time; - time += evtPos.timeDelay; + evtPos.absPos = abs_position; + abs_position += evtPos.delay; evtPos.sortEvents(); trackDataNew[tk].push_back(evtPos); evtPos.reset(); + gotLoopEventInThisRow = false; } - } while(event.subtype != MidiEvent::ST_ENDTRACK); - - // Build the chain of events - for(size_t i = 0, j = 1; i < trackDataNew[tk].size() && j < trackDataNew[tk].size(); i++, j++) - trackDataNew[tk][i].next = &(trackDataNew[tk][j]); + } 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][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<uint64_t> currentTempo = Tempo; + double time = 0.0; + uint8_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<TempoChangePoint> points; + fraction<uint64_t> 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<uint64_t>(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<uint64_t> t = pos.delay * currentTempo; + pos.timeDelay = t.value(); + pos.time = time; + time += pos.timeDelay; + + 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; + trackBeginPositionNew = CurrentPositionNew; + + return true; } MIDIplay::MIDIplay(): cmf_percussion_mode(false), - config(NULL), + fullSongTimeLength(0.0), + postSongWaitDelay(1.0), + loopStartTime(-1.0), + loopEndTime(-1.0), + tempoMultiplier(1.0), trackStart(false), atEnd(false), loopStart(false), loopEnd(false), - loopStart_passed(false), - invalidLoop(false), - loopStart_hit(false) + invalidLoop(false) { devices.clear(); + + m_setup.AdlBank = 0; + m_setup.NumFourOps = 7; + m_setup.NumCards = 2; + m_setup.HighTremoloMode = false; + m_setup.HighVibratoMode = false; + m_setup.AdlPercussionMode = false; + m_setup.LogarithmicVolumes = false; + m_setup.SkipForward = 0; + m_setup.loopingIsEnabled = false; + m_setup.ScaleModulators = false; + m_setup.delay = 0.0; + m_setup.carry = 0.0; + m_setup.stored_samples = 0; + m_setup.backup_samples_size = 0; + + opl.NumCards = m_setup.NumCards; + opl.AdlBank = m_setup.AdlBank; + opl.NumFourOps = m_setup.NumFourOps; + opl.LogarithmicVolumes = m_setup.LogarithmicVolumes; + opl.HighTremoloMode = m_setup.HighTremoloMode; + opl.HighVibratoMode = m_setup.HighVibratoMode; + opl.AdlPercussionMode = m_setup.AdlPercussionMode; + opl.ScaleModulators = m_setup.ScaleModulators; } uint64_t MIDIplay::ReadVarLen(uint8_t **ptr) @@ -277,24 +511,33 @@ uint64_t MIDIplay::ReadVarLen(uint8_t **ptr) return result; } -uint64_t MIDIplay::ReadVarLen(size_t tk) +uint64_t MIDIplay::ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok) { uint64_t result = 0; + ok = false; + for(;;) { - uint8_t byte = TrackData[tk][CurrentPosition.track[tk].ptr++]; + if(*ptr >= end) + return 2; + unsigned char byte = *((*ptr)++); result = (result << 7) + (byte & 0x7F); - if(!(byte & 0x80)) - break; + if(!(byte & 0x80)) break; } + + ok = true; return result; } double MIDIplay::Tick(double s, double granularity) { - //if(CurrentPositionNew.began) + 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)) @@ -316,42 +559,100 @@ double MIDIplay::Tick(double s, double granularity) UpdateVibrato(s); UpdateArpeggio(s); + if(CurrentPositionNew.wait < 0.0)//Avoid negative delay value! + return 0.0; + return CurrentPositionNew.wait; -// if(CurrentPosition.began) -// CurrentPosition.wait -= s; +} -// int antiFreezeCounter = 10000;//Limit 10000 loops to avoid freezing -// while((CurrentPosition.wait <= granularity * 0.5) && (antiFreezeCounter > 0)) -// { -// //std::fprintf(stderr, "wait = %g...\n", CurrentPosition.wait); -// if(!ProcessEvents()) -// break; -// if(CurrentPosition.wait <= 0.0) -// antiFreezeCounter--; -// } +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; + + bool loopFlagState = m_setup.loopingIsEnabled; + 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(); + 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; -// if(antiFreezeCounter <= 0) -// CurrentPosition.wait += 1.0;/* Add extra 1 second when over 10000 events -// with zero delay are been detected */ + m_setup.loopingIsEnabled = loopFlagState; + m_setup.delay = CurrentPositionNew.wait; + m_setup.carry = 0.0; +} + +double MIDIplay::tell() +{ + return CurrentPositionNew.absTimePosition; +} -// for(uint16_t c = 0; c < opl.NumChannels; ++c) -// ch[c].AddAge(static_cast<int64_t>(s * 1000.0)); +double MIDIplay::timeLength() +{ + return fullSongTimeLength; +} -// UpdateVibrato(s); -// UpdateArpeggio(s); +double MIDIplay::getLoopStart() +{ + return loopStartTime; +} -// return CurrentPosition.wait; +double MIDIplay::getLoopEnd() +{ + return loopEndTime; } void MIDIplay::rewind() { - CurrentPosition = trackBeginPosition; + Panic(); + KillSustainingNotes(-1, -1); + CurrentPositionNew = trackBeginPositionNew; trackStart = true; atEnd = false; loopStart = true; - loopStart_passed = false; invalidLoop = false; - loopStart_hit = false; +} + +void MIDIplay::setTempo(double tempo) +{ + tempoMultiplier = tempo; } void MIDIplay::realTime_ResetState() @@ -562,10 +863,8 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) for(unsigned ccount = 0; ccount < 2; ++ccount) { int32_t c = adlchannel[ccount]; - if(c < 0) continue; - ir.first->second.phys[ static_cast<uint16_t>(adlchannel[ccount]) ] = i[ccount]; } NoteUpdate(channel, ir.first, Upd_All | Upd_Patch); @@ -976,153 +1275,77 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, } -bool MIDIplay::ProcessEvents() +bool MIDIplay::ProcessEventsNew(bool isSeek) { - if(TrackData.size() == 0) + 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 = TrackData.size(); - const Position RowBeginPosition(CurrentPosition); - - for(size_t tk = 0; tk < TrackCount; ++tk) - { - if(CurrentPosition.track[tk].status >= 0 - && CurrentPosition.track[tk].delay <= 0) - { - // Handle event - HandleEvent(tk); - - // Read next event time (unless the track just ended) - if(CurrentPosition.track[tk].ptr >= TrackData[tk].size()) - CurrentPosition.track[tk].status = -1; - - if(CurrentPosition.track[tk].status >= 0) - CurrentPosition.track[tk].delay += ReadVarLen(tk); - } - } - - // Find shortest delay from all track - uint64_t shortest = 0; - bool shortest_no = true; - - for(size_t tk = 0; tk < TrackCount; ++tk) - if((CurrentPosition.track[tk].status >= 0) && (shortest_no || CurrentPosition.track[tk].delay < shortest)) - { - shortest = CurrentPosition.track[tk].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) - CurrentPosition.track[tk].delay -= shortest; - - fraction<uint64_t> t = shortest * Tempo; - - if(CurrentPosition.began) - CurrentPosition.wait += t.valuel(); - - //if(shortest > 0) UI.PrintLn("Delay %ld (%g)", shortest, (double)t.valuel()); - /* - if(CurrentPosition.track[0].ptr > 8119) - loopEnd = true; - // ^HACK: CHRONO TRIGGER LOOP - */ - - if(loopStart_hit && (loopStart || loopEnd)) //Avoid invalid loops - { - invalidLoop = true; - loopStart = false; - loopEnd = false; - LoopBeginPosition = trackBeginPosition; - } - else - loopStart_hit = false; - - if(loopStart) - { - if(trackStart) - { - trackBeginPosition = RowBeginPosition; - trackStart = false; - atEnd = false; - } - LoopBeginPosition = RowBeginPosition; - loopStart = false; - loopStart_hit = true; - } - - if(shortest_no || loopEnd) - { - //Loop if song end or loop end point has reached - loopEnd = false; - shortest = 0; - if(opl._parent->loopingIsEnabled == 0) - { - atEnd = true; //Don't handle events anymore - CurrentPosition.wait += 1.0;//One second delay until stop playing - return true;//We have caugh end here! - } - CurrentPosition = LoopBeginPosition; - } - - return true;//Has events in queue -} - -bool MIDIplay::ProcessEventsNew() -{ - if(TrackData.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 = TrackData.size(); + 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) { - if(CurrentPositionNew.track[tk].status >= 0 - && CurrentPositionNew.track[tk].delay <= 0) + PositionNew::TrackInfo &track = CurrentPositionNew.track[tk]; + if((track.status >= 0) && (track.delay <= 0)) { // Handle event - for(size_t i = 0; i < CurrentPositionNew.track[tk].pos->events.size(); i++) + for(size_t i = 0; i < track.pos->events.size(); i++) { - MidiEvent &evt = CurrentPositionNew.track[tk].pos->events[i]; - HandleEvent(tk, evt, CurrentPositionNew.track[tk].status); + 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! } - std::fprintf(stdout, "Time: %f\r", CurrentPositionNew.track[tk].pos->time); - std::fflush(stdout); + #ifdef DEBUG_TIME_CALCULATION + if(maxTime < track.pos->time) + maxTime = track.pos->time; + #endif // Read next event time (unless the track just ended) - if(CurrentPositionNew.track[tk].pos->next == NULL/* >= TrackData[tk].size()*/) - CurrentPositionNew.track[tk].status = -1; + if(track.pos == trackDataNew[tk].end()) + track.status = -1; - if(CurrentPositionNew.track[tk].status >= 0) - CurrentPositionNew.track[tk].delay += CurrentPositionNew.track[tk].pos->delay; - - if(CurrentPositionNew.track[tk].status >= 0) - CurrentPositionNew.track[tk].pos = CurrentPositionNew.track[tk].pos->next; + if(track.status >= 0) + { + track.delay += track.pos->delay; + track.pos++; + } } } + #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) - if((CurrentPositionNew.track[tk].status >= 0) && (shortest_no || CurrentPositionNew.track[tk].delay < shortest)) + { + PositionNew::TrackInfo &track = CurrentPositionNew.track[tk]; + if((track.status >= 0) && (shortest_no || track.delay < shortest)) { - shortest = CurrentPositionNew.track[tk].delay; + shortest = track.delay; shortest_no = false; } + } //if(shortest > 0) UI.PrintLn("shortest: %ld", shortest); @@ -1132,37 +1355,17 @@ bool MIDIplay::ProcessEventsNew() fraction<uint64_t> t = shortest * Tempo; - //if(CurrentPositionNew.began) - CurrentPositionNew.wait += t.valuel(); - - //if(shortest > 0) UI.PrintLn("Delay %ld (%g)", shortest, (double)t.valuel()); - /* - if(CurrentPosition.track[0].ptr > 8119) - loopEnd = true; - // ^HACK: CHRONO TRIGGER LOOP - */ + #ifdef ENABLE_BEGIN_SILENCE_SKIPPING + if(CurrentPositionNew.began) + #endif + CurrentPositionNew.wait += t.value(); - if(loopStart_hit && (loopStart || loopEnd)) //Avoid invalid loops - { - invalidLoop = true; - loopStart = false; - loopEnd = false; - LoopBeginPositionNew = trackBeginPositionNew; - } - else - loopStart_hit = false; + //if(shortest > 0) UI.PrintLn("Delay %ld (%g)", shortest, (double)t.valuel()); if(loopStart) { - if(trackStart) - { - trackBeginPositionNew = RowBeginPosition; - trackStart = false; - atEnd = false; - } LoopBeginPositionNew = RowBeginPosition; loopStart = false; - loopStart_hit = true; } if(shortest_no || loopEnd) @@ -1170,10 +1373,10 @@ bool MIDIplay::ProcessEventsNew() //Loop if song end or loop end point has reached loopEnd = false; shortest = 0; - if(opl._parent->loopingIsEnabled == 0) + if(!m_setup.loopingIsEnabled) { atEnd = true; //Don't handle events anymore - CurrentPositionNew.wait += 1.0;//One second delay until stop playing + CurrentPositionNew.wait += postSongWaitDelay;//One second delay until stop playing return true;//We have caugh end here! } CurrentPositionNew = LoopBeginPositionNew; @@ -1182,24 +1385,45 @@ bool MIDIplay::ProcessEventsNew() return true;//Has events in queue } -MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t**pptr, int &status) +MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t**pptr, uint8_t *end, int &status) { uint8_t *&ptr = *pptr; MIDIplay::MidiEvent evt; + + if(ptr + 1 > end) + { + errorString += "parseEvent: Can't read event type byte - Unexpected end of track data.\n"; + evt.isValid = 0; + return evt; + } + unsigned char byte = *(ptr++); + bool ok = false; - if(byte == 0xF7 || byte == 0xF0) // Ignore SysEx + if(byte == MidiEvent::T_SYSEX || byte == MidiEvent::T_SYSEX2)// Ignore SysEx { - uint64_t length = ReadVarLen(pptr); + 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 == 0xFF) + if(byte == MidiEvent::T_SPECIAL) { // Special event FF uint8_t evtype = *(ptr++); - uint64_t length = ReadVarLen(pptr); + 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; @@ -1207,8 +1431,62 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t**pptr, int &status) evt.subtype = evtype; evt.data.insert(evt.data.begin(), data.begin(), data.end()); + /* 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) + { + //TODO: Implement own field for this + //TODO: Implement API call to retreive this + //TODO: Implement a hook to catch this + std::string str((const char*)evt.data.data(), evt.data.size()); + std::fprintf(stdout, "Copyright: %s\n", str.c_str()); + std::fflush(stdout); + } + else + if(evt.subtype == MidiEvent::ST_SQTRKTITLE) + { + //TODO: Implement API call to retreive this + //TODO: Implement a hook to catch this + if(musTitle.empty()) + musTitle = std::string((const char*)evt.data.data(), evt.data.size()); + } + else + if(evt.subtype == MidiEvent::ST_INSTRTITLE) + { + //TODO: Implement a hook to catch this + std::string str((const char*)evt.data.data(), evt.data.size()); + std::fprintf(stdout, "Instrument: %s\n", str.c_str()); + std::fflush(stdout); + } + 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; + status = -1;//Finalize track return evt; } @@ -1220,313 +1498,151 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t**pptr, int &status) ptr--; } - if(byte == 0xF3) + //Sys Com Song Select(Song #) [0-127] + if(byte == MidiEvent::T_SYSCOMSNGSEL) { - ptr += 1; - return evt; - } - - if(byte == 0xF2) - { - ptr += 2; + 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; } - uint8_t MidCh = byte & 0x0F, EvType = byte >> 4; - status = byte; - evt.channel = MidCh; - evt.type = EvType; - - switch(EvType) - { - case 0x8: // Note off - case 0x9: // Note on - case 0xA: // Note touch - case 0xB: // Controller change - case 0xE: // Wheel/pitch bend + //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; } - case 0xC: // Patch change - case 0xD: // Channel after-touch - { - evt.data.push_back(*(ptr++)); - return evt; - } - } - - return evt; -} - -void MIDIplay::HandleEvent(size_t tk) -{ - unsigned char byte = TrackData[tk][CurrentPosition.track[tk].ptr++]; - - if(byte == 0xF7 || byte == 0xF0) // Ignore SysEx - { - uint64_t length = ReadVarLen(tk); - //std::string data( length?(const char*) &TrackData[tk][CurrentPosition.track[tk].ptr]:0, length ); - CurrentPosition.track[tk].ptr += (size_t)length; - //UI.PrintLn("SysEx %02X: %u bytes", byte, length/*, data.c_str()*/); - return; - } + uint8_t midCh = byte & 0x0F, evType = (byte >> 4) & 0x0F; + status = byte; + evt.channel = midCh; + evt.type = evType; - if(byte == 0xFF) + switch(evType) { - // Special event FF - uint8_t evtype = TrackData[tk][CurrentPosition.track[tk].ptr++]; - uint64_t length = ReadVarLen(tk); - std::string data(length ? (const char *) &TrackData[tk][CurrentPosition.track[tk].ptr] : 0, (size_t)length); - CurrentPosition.track[tk].ptr += (size_t)length; - - if(evtype == 0x2F)//End Of Track - { - CurrentPosition.track[tk].status = -1; - return; - } - - if(evtype == 0x51)//Tempo change + 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) { - Tempo = InvDeltaTicks * fraction<uint64_t>(ReadBEint(data.data(), data.size())); - return; + errorString += "parseEvent: Can't read regular 2-byte event - Unexpected end of track data.\n"; + evt.isValid = 0; + return evt; } - if(evtype == 6)//Meta event - { - //Turn on/off Loop handling when loop is disabled - if(opl._parent->loopingIsEnabled != 0) - { - /* Move this away from events handler */ - 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") && (!invalidLoop)) - { - loopStart = true; - loopStart_passed = true; - } - - if((data == "loopend") && (!invalidLoop)) - { - if((loopStart_passed) && (!loopStart)) - loopEnd = true; - else - invalidLoop = true; - } - } - } - - if(evtype == 9) - current_device[tk] = ChooseDevice(data); - - //if(evtype >= 1 && evtype <= 6) - // UI.PrintLn("Meta %d: %s", evtype, data.c_str()); + evt.data.push_back(*(ptr++)); + evt.data.push_back(*(ptr++)); - if(evtype == 0xE3) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib + //111'th loopStart controller (RPG Maker and others) + if((evType == MidiEvent::T_CTRLCHANGE) && (evt.data[0] == 111)) { - uint8_t i = static_cast<uint8_t>(data[0]), v = static_cast<uint8_t>(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); + //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; - } - - // Any normal event (80..EF) - if(byte < 0x80) - { - byte = static_cast<uint8_t>(CurrentPosition.track[tk].status | 0x80); - CurrentPosition.track[tk].ptr--; - } - - if(byte == 0xF3) - { - CurrentPosition.track[tk].ptr += 1; - return; - } - - if(byte == 0xF2) - { - CurrentPosition.track[tk].ptr += 2; - 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 = byte & 0x0F, EvType = byte >> 4; - MidCh += (uint8_t)current_device[tk]; - CurrentPosition.track[tk].status = byte; - - switch(EvType) - { - case 0x8: // Note off - { - uint8_t note = TrackData[tk][CurrentPosition.track[tk].ptr++]; - /*uint8_t vol=*/TrackData[tk][CurrentPosition.track[tk].ptr++]; - //if(MidCh != 9) note -= 12; // HACK - realTime_NoteOff(MidCh, note); - break; - } - case 0x9: // Note on - { - uint8_t note = TrackData[tk][CurrentPosition.track[tk].ptr++]; - uint8_t vol = TrackData[tk][CurrentPosition.track[tk].ptr++]; - //if(MidCh != 9) note -= 12; // HACK - if(realTime_NoteOn(MidCh, note, vol)) - CurrentPosition.began = true; - break; - } - - case 0xA: // Note touch - { - uint8_t note = TrackData[tk][CurrentPosition.track[tk].ptr++]; - uint8_t vol = TrackData[tk][CurrentPosition.track[tk].ptr++]; - realTime_NoteAfterTouch(MidCh, note, vol); - break; - } - - case 0xB: // Controller change - { - uint8_t ctrlno = TrackData[tk][CurrentPosition.track[tk].ptr++]; - uint8_t value = TrackData[tk][CurrentPosition.track[tk].ptr++]; - - if((opl._parent->loopingIsEnabled != 0) && (ctrlno == 111) && !invalidLoop) + return evt; + case MidiEvent::T_PATCHCHANGE://1 byte length + case MidiEvent::T_CHANAFTTOUCH: + if(ptr + 1 > end) { - loopStart = true; - loopStart_passed = true; - break; + errorString += "parseEvent: Can't read regular 1-byte event - Unexpected end of track data.\n"; + evt.isValid = 0; + return evt; } - - realTime_Controller(MidCh, ctrlno, value); - break; - } - - case 0xC: // Patch change - realTime_PatchChange(MidCh, TrackData[tk][CurrentPosition.track[tk].ptr++]); - break; - - case 0xD: // Channel after-touch - { - // TODO: Verify, is this correct action? - uint8_t vol = TrackData[tk][CurrentPosition.track[tk].ptr++]; - realTime_ChannelAfterTouch(MidCh, vol); - break; + evt.data.push_back(*(ptr++)); + return evt; } - case 0xE: // Wheel/pitch bend - { - uint8_t a = TrackData[tk][CurrentPosition.track[tk].ptr++]; - uint8_t b = TrackData[tk][CurrentPosition.track[tk].ptr++]; - realTime_PitchBend(MidCh, b, a); - break; - } - } + return evt; } + void MIDIplay::HandleEvent(size_t tk, MIDIplay::MidiEvent &evt, int &status) { - if(evt.type == 0xF7 || evt.type == 0xF0) // Ignore SysEx + 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 == 0xFF) + 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 == 0x2F)//End Of Track + if(evtype == MidiEvent::ST_ENDTRACK)//End Of Track { status = -1; return; } - if(evtype == 0x51)//Tempo change + if(evtype == MidiEvent::ST_TEMPOCHANGE)//Tempo change { Tempo = InvDeltaTicks * fraction<uint64_t>(ReadBEint(evt.data.data(), evt.data.size())); return; } - if(evtype == 6)//Meta event + if(evtype == MidiEvent::ST_MARKER)//Meta event { - //Turn on/off Loop handling when loop is disabled - if(opl._parent->loopingIsEnabled != 0) - { - /* Move this away from events handler */ - 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") && (!invalidLoop)) - { - loopStart = true; - loopStart_passed = true; - } - - if((data == "loopend") && (!invalidLoop)) - { - if((loopStart_passed) && (!loopStart)) - loopEnd = true; - else - invalidLoop = true; - } - } + //Do nothing! :-P + return; } - if(evtype == 9) + 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()); - if(evtype == 0xE1) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib + //Turn on Loop handling when loop is enabled + if(m_setup.loopingIsEnabled && !invalidLoop) { - if(!invalidLoop) + if(evtype == MidiEvent::ST_LOOPSTART) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib { loopStart = true; - loopStart_passed = true; + return; } - } - if(evtype == 0xE2) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib - { - if(!invalidLoop) + if(evtype == MidiEvent::ST_LOOPEND) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib { - if((loopStart_passed) && (!loopStart)) - loopEnd = true; - else - invalidLoop = true; + loopEnd = true; + return; } } - if(evtype == 0xE3) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib + if(evtype == MidiEvent::ST_RAWOPL) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib { uint8_t i = static_cast<uint8_t>(data[0]), v = static_cast<uint8_t>(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; @@ -1539,86 +1655,68 @@ void MIDIplay::HandleEvent(size_t tk, MIDIplay::MidiEvent &evt, int &status) // CurrentPosition.track[tk].ptr--; // } - if(evt.type == 0xF3) - { - //CurrentPosition.track[tk].ptr += 1; - return; - } - - if(evt.type == 0xF2) - { - //CurrentPosition.track[tk].ptr += 2; + 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]; + uint8_t midCh = evt.channel;//byte & 0x0F, EvType = byte >> 4; + midCh += (uint8_t)current_device[tk]; status = evt.type; switch(evt.type) { - case 0x8: // Note off + case MidiEvent::T_NOTEOFF: // Note off { uint8_t note = evt.data[0]; - /*uint8_t vol=*/ //TrackData[tk][CurrentPosition.track[tk].ptr++]; - //if(MidCh != 9) note -= 12; // HACK - realTime_NoteOff(MidCh, note); + realTime_NoteOff(midCh, note); break; } - case 0x9: // Note on + + case MidiEvent::T_NOTEON: // Note on { - uint8_t note = evt.data[0];//TrackData[tk][CurrentPosition.track[tk].ptr++]; - uint8_t vol = evt.data[1];//TrackData[tk][CurrentPosition.track[tk].ptr++]; - //if(MidCh != 9) note -= 12; // HACK - if(realTime_NoteOn(MidCh, note, vol)) - CurrentPosition.began = true; + uint8_t note = evt.data[0]; + uint8_t vol = evt.data[1]; + /*if(*/ realTime_NoteOn(midCh, note, vol); /*)*/ + //CurrentPosition.began = true; break; } - case 0xA: // Note touch + case MidiEvent::T_NOTETOUCH: // Note touch { - uint8_t note = evt.data[0];//TrackData[tk][CurrentPosition.track[tk].ptr++]; - uint8_t vol = evt.data[1];//TrackData[tk][CurrentPosition.track[tk].ptr++]; - realTime_NoteAfterTouch(MidCh, note, vol); + uint8_t note = evt.data[0]; + uint8_t vol = evt.data[1]; + realTime_NoteAfterTouch(midCh, note, vol); break; } - case 0xB: // Controller change + case MidiEvent::T_CTRLCHANGE: // Controller change { - uint8_t ctrlno = evt.data[0];//TrackData[tk][CurrentPosition.track[tk].ptr++]; - uint8_t value = evt.data[1];//TrackData[tk][CurrentPosition.track[tk].ptr++]; - - if((opl._parent->loopingIsEnabled != 0) && (ctrlno == 111) && !invalidLoop) - { - loopStart = true; - loopStart_passed = true; - break; - } - - realTime_Controller(MidCh, ctrlno, value); + uint8_t ctrlno = evt.data[0]; + uint8_t value = evt.data[1]; + realTime_Controller(midCh, ctrlno, value); break; } - case 0xC: // Patch change - realTime_PatchChange(MidCh, evt.data[0] /*TrackData[tk][CurrentPosition.track[tk].ptr++]*/); + case MidiEvent::T_PATCHCHANGE: // Patch change + realTime_PatchChange(midCh, evt.data[0]); break; - case 0xD: // Channel after-touch + case MidiEvent::T_CHANAFTTOUCH: // Channel after-touch { // TODO: Verify, is this correct action? - uint8_t vol = evt.data[0];//TrackData[tk][CurrentPosition.track[tk].ptr++]; - realTime_ChannelAfterTouch(MidCh, vol); + uint8_t vol = evt.data[0]; + realTime_ChannelAfterTouch(midCh, vol); break; } - case 0xE: // Wheel/pitch bend + case MidiEvent::T_WHEEL: // Wheel/pitch bend { - uint8_t a = evt.data[0];//TrackData[tk][CurrentPosition.track[tk].ptr++]; - uint8_t b = evt.data[1];//TrackData[tk][CurrentPosition.track[tk].ptr++]; - realTime_PitchBend(MidCh, b, a); + uint8_t a = evt.data[0]; + uint8_t b = evt.data[1]; + realTime_PitchBend(midCh, b, a); break; } } @@ -1688,11 +1786,8 @@ long MIDIplay::CalculateAdlChannelGoodness(unsigned c, uint16_t ins, uint16_t) c ++m) { if(m->second.sustained) continue; - if(m->second.vibdelay >= 200) continue; - if(m->second.ins != j->second.ins) continue; - n_evacuation_stations += 1; } } @@ -1813,6 +1908,15 @@ void MIDIplay::KillOrEvacuate(size_t from_channel, AdlChannel::users_t::iterator static_cast<int32_t>(from_channel)); } +void MIDIplay::Panic() +{ + for(uint8_t chan = 0; chan < Ch.size(); chan++) + { + for(uint8_t note = 0; note < 128; note++) + realTime_NoteOff(chan, note); + } +} + void MIDIplay::KillSustainingNotes(int32_t MidCh, int32_t this_adlchn) { uint32_t first = 0, last = opl.NumChannels; diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index 316c8e1..4878233 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -406,7 +406,7 @@ void OPL3::ChangeVolumeRangesModel(ADLMIDI_VolumeModels volumeModel) } } -void OPL3::Reset() +void OPL3::Reset(unsigned long PCM_RATE) { #ifdef ADLMIDI_USE_DOSBOX_OPL DBOPL::Handler emptyChip; //Constructors inside are will initialize necessary fields @@ -445,9 +445,9 @@ void OPL3::Reset() for(unsigned card = 0; card < NumCards; ++card) { #ifdef ADLMIDI_USE_DOSBOX_OPL - cards[card].Init(_parent->PCM_RATE); + cards[card].Init(PCM_RATE); #else - OPL3_Reset(&cards[card], static_cast<Bit32u>(_parent->PCM_RATE)); + OPL3_Reset(&cards[card], static_cast<Bit32u>(PCM_RATE)); #endif for(unsigned a = 0; a < 18; ++a) Poke(card, 0xB0 + Channels[a], 0x00); diff --git a/src/adlmidi_private.cpp b/src/adlmidi_private.cpp index c888b18..04bb481 100644 --- a/src/adlmidi_private.cpp +++ b/src/adlmidi_private.cpp @@ -47,7 +47,7 @@ int adlRefreshNumCards(ADL_MIDIPlayer *device) //For embedded bank for(unsigned a = 0; a < 256; ++a) { - unsigned insno = banks[device->AdlBank][a]; + unsigned insno = banks[play->m_setup.AdlBank][a]; if(insno == 198) continue; ++n_total[a / 128]; @@ -57,13 +57,13 @@ int adlRefreshNumCards(ADL_MIDIPlayer *device) } } - 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); - play->opl.NumFourOps = device->NumFourOps; + play->m_setup.NumFourOps = + (n_fourop[0] >= n_total[0] * 7 / 8) ? play->m_setup.NumCards * 6 + : (n_fourop[0] < n_total[0] * 1 / 8) ? 0 + : (play->m_setup.NumCards == 1 ? 1 : play->m_setup.NumCards * 4); + play->opl.NumFourOps = play->m_setup.NumFourOps; - if(n_fourop[0] >= n_total[0] * 15 / 16 && device->NumFourOps == 0) + if(n_fourop[0] >= n_total[0] * 15 / 16 && play->m_setup.NumFourOps == 0) { ADLMIDI_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" diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index d3709a2..622e9f2 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -50,6 +50,7 @@ #endif #include <vector> +#include <list> #include <string> #include <sstream> #include <map> @@ -155,7 +156,7 @@ public: VOLUME_CMF, VOLUME_DMX, VOLUME_APOGEE, - VOLUME_9X, + VOLUME_9X } m_volumeScale; OPL3(); @@ -180,31 +181,37 @@ public: void Silence(); void updateFlags(); void ChangeVolumeRangesModel(ADLMIDI_VolumeModels volumeModel); - void Reset(); + void Reset(unsigned long PCM_RATE); }; +/* + * TODO: Put usage of those hooks to the places where originally was UI usage. + * Also, provide external API to set those hooks + */ -class MIDIplay +/** + * @brief Hooks of the internal events + */ +struct MIDIEventHooks { - // Information about each track - struct Position - { - bool began; - char padding[7]; - double wait; - struct TrackInfo - { - size_t ptr; - uint64_t delay; - int status; - char padding2[4]; - TrackInfo(): ptr(0), delay(0), status(0) {} - }; - std::vector<TrackInfo> track; - - Position(): began(false), wait(0.0l), track() { } - } CurrentPosition, LoopBeginPosition, trackBeginPosition; + //! Raw MIDI event hook + typedef void (*RawEventHook)(void *userdata, uint8_t type, uint8_t subtype, uint8_t channel, 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); + NoteHook onNote; + void *onNote_userData; + + //! Library internal debug messages + typedef void (*DebugMessageHook)(void *userdata, const char *fmt, ...); + DebugMessageHook onDebugMessage; + void *onDebugMessage_userData; +}; +class MIDIplay +{ std::map<std::string, uint64_t> devices; std::map<uint64_t /*track*/, uint64_t /*channel begin index*/> current_device; @@ -293,9 +300,10 @@ class MIDIplay AdlChannel(): users(), koff_time_until_neglible(0) { } void AddAge(int64_t ms); }; -public: + + //Padding to fix CLanc code model's warning char ____padding[7]; -private: + std::vector<AdlChannel> ch; std::vector<std::vector<uint8_t> > TrackData; @@ -310,29 +318,44 @@ private: enum Types { T_UNKNOWN = 0x00, - T_NOTEOFF = 0x08, - T_NOTEON = 0x09, - T_NOTETOUCH = 0x0A, - T_CTRLCHANGE = 0x0B, - T_PATCHCHANGE = 0x0C, - T_CHANAFTTOUCH = 0x0D, - T_WHEEL = 0x0E, - - T_SYSEX = 0xF7, - T_SYSEX2 = 0xF0, - T_SPECIAL = 0xFF, + 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_UNKNOWN = 0x00, - ST_ENDTRACK = 0x2F, - ST_TEMPOCHANGE = 0x51, - ST_META = 0x06, + 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 <CUSTOM> + 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, - ST_LOOPEND = 0xE2, - ST_RAWOPL = 0xE3, + ST_LOOPSTART = 0xE1,//size == 0 <CUSTOM> + ST_LOOPEND = 0xE2,//size == 0 <CUSTOM> + ST_RAWOPL = 0xE3//size == 0 <CUSTOM> }; //! Main type of event uint8_t type; @@ -340,9 +363,12 @@ private: uint8_t subtype; //! Targeted MIDI channel uint8_t channel; - + //! Is valid event + uint8_t isValid; //! Reserved 5 bytes padding - uint8_t __padding[5]; + uint8_t __padding[4]; + //! Absolute tick position (Used for the tempo calculation only) + uint64_t absPosition; //! Raw data of this event std::vector<uint8_t> data; }; @@ -353,15 +379,17 @@ private: * 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) */ - class MidiTrackPos + class MidiTrackRow { public: - MidiTrackPos(); + 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<MidiEvent> events; @@ -369,65 +397,142 @@ private: * @brief Sort events in this position */ void sortEvents(); - //! Next event that follows current - MidiTrackPos *next; }; + /** + * @brief Tempo change point entry. Used in the MIDI data building function only. + */ + struct TempoChangePoint + { + uint64_t absPos; + fraction<uint64_t> 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<MidiTrackRow> 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]; - MidiTrackPos *pos; - TrackInfo(): ptr(0), delay(0), status(0), pos(NULL) {} + MidiTrackQueue::iterator pos; + TrackInfo(): ptr(0), delay(0), status(0) {} }; std::vector<TrackInfo> track; - PositionNew(): began(false), wait(0.0), track() + PositionNew(): began(false), wait(0.0), absTimePosition(0.0), track() {} } CurrentPositionNew, LoopBeginPositionNew, trackBeginPositionNew; - std::vector<std::vector<MidiTrackPos> > trackDataNew; - std::vector<int> trackDataNewStatus; - void buildTrackData(); - MidiEvent parseEvent(uint8_t **ptr, int &status); + //! 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; + //! Local error string + std::string errorString; + + //! Pre-processed track data storage + std::vector<MidiTrackQueue > trackDataNew; + + /** + * @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); public: MIDIplay(); ~MIDIplay() {} - ADL_MIDIPlayer *config; std::string musTitle; fraction<uint64_t> InvDeltaTicks, Tempo; + //! Tempo multiplier + double tempoMultiplier; bool trackStart, atEnd, loopStart, loopEnd, - loopStart_passed /*Tells that "loopStart" already passed*/, - invalidLoop /*Loop points are invalid (loopStart after loopEnd or loopStart and loopEnd are on same place)*/, - loopStart_hit /*loopStart entry was hited in previous tick*/; + invalidLoop; /*Loop points are invalid (loopStart after loopEnd or loopStart and loopEnd are on same place)*/ char ____padding2[2]; OPL3 opl; - //! Generated per-tick audio output buffer + int16_t outBuf[1024]; -public: + + struct Setup + { + unsigned int AdlBank; + unsigned int NumFourOps; + unsigned int NumCards; + bool HighTremoloMode; + bool HighVibratoMode; + bool AdlPercussionMode; + bool LogarithmicVolumes; + int VolumeModel; + unsigned int SkipForward; + bool loopingIsEnabled; + bool ScaleModulators; + + double delay; + double carry; + + /* The lag between visual content and audio content equals */ + /* the sum of these two buffers. */ + double mindelay; + double maxdelay; + + /* For internal usage */ + ssize_t stored_samples; /* num of collected samples */ + short backup_samples[1024]; /* Backup sample storage. */ + ssize_t backup_samples_size; /* Backup sample storage. */ + /* For internal usage */ + + unsigned long PCM_RATE; + } 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 + */ uint64_t ReadVarLen(uint8_t **ptr); - uint64_t ReadVarLen(size_t tk); - uint64_t ReadVarLenEx(size_t tk, bool &ok); + /** + * @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); /* * A little class gives able to read filedata from disk and also from a memory segment - */ + */ class fileReader { public: @@ -565,7 +670,10 @@ public: bool eof() { - return mp_tell >= mp_size; + if(fp) + return std::feof(fp); + else + return mp_tell >= mp_size; } std::string _fileName; std::FILE *fp; @@ -582,15 +690,55 @@ public: bool LoadMIDI(void *data, unsigned long size); bool LoadMIDI(fileReader &fr); - /* Periodic tick handler. - * Input: s = seconds since last call - * Input: granularity = don't expect intervals smaller than this, in seconds - * Output: desired number of seconds until next call + /** + * @brief Periodic tick handler. + * @param s seconds since last call + * @param granularity don't expect intervals smaller than this, in seconds + * @return desired number of seconds until next call */ double Tick(double s, double granularity); + /** + * @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); + /* RealTime event triggers */ void realTime_ResetState(); @@ -627,7 +775,7 @@ private: unsigned props_mask, int32_t select_adlchn = -1); bool ProcessEvents(); - bool ProcessEventsNew(); + bool ProcessEventsNew(bool isSeek = false); void HandleEvent(size_t tk); void HandleEvent(size_t tk, MidiEvent &evt, int &status); @@ -643,6 +791,7 @@ private: size_t from_channel, AdlChannel::users_t::iterator 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) diff --git a/src/dbopl.cpp b/src/dbopl.cpp index cd857f4..fb28e20 100644 --- a/src/dbopl.cpp +++ b/src/dbopl.cpp @@ -1997,7 +1997,7 @@ namespace DBOPL Bit32s out32[1024]; if(GCC_UNLIKELY(*samples > 512)) *samples = 512; - memset(out32, 0, sizeof(Bit32s) * size_t(*samples) * 2); + memset(out32, 0, sizeof(Bit32s) * 1024); if(!chip.opl3Active) chip.GenerateBlock2(static_cast<Bitu>(*samples), out32); else @@ -2011,7 +2011,6 @@ namespace DBOPL { if(GCC_UNLIKELY(*samples > 512)) *samples = 512; - if(!chip.opl3Active) chip.GenerateBlock2_Mix(static_cast<Bitu>(*samples), out); else @@ -2023,11 +2022,11 @@ namespace DBOPL Bit32s out32[1024]; if(GCC_UNLIKELY(*samples > 512)) *samples = 512; - memset(out32, 0, sizeof(Bit32s) * size_t(*samples) * 2); + memset(out32, 0, sizeof(Bit32s) * 1024); if(!chip.opl3Active) - chip.GenerateBlock2_Mix(static_cast<Bitu>(*samples), out32); + chip.GenerateBlock2(static_cast<Bitu>(*samples), out32); else - chip.GenerateBlock3_Mix(static_cast<Bitu>(*samples), out32); + chip.GenerateBlock3(static_cast<Bitu>(*samples), out32); ssize_t sz = *samples * 2; for(ssize_t i = 0; i < sz; i++) out[i] += static_cast<Bit16s>(DBOPL_CLAMP(out32[i], static_cast<ssize_t>(INT16_MIN), static_cast<ssize_t>(INT16_MAX))); diff --git a/src/dbopl.h b/src/dbopl.h index d6091a2..826cb44 100644 --- a/src/dbopl.h +++ b/src/dbopl.h @@ -84,14 +84,14 @@ namespace DBOPL 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 @@ -103,7 +103,7 @@ namespace DBOPL MASK_KSR = 0x10, MASK_SUSTAIN = 0x20, MASK_VIBRATO = 0x40, - MASK_TREMOLO = 0x80, + MASK_TREMOLO = 0x80 }; typedef enum @@ -112,7 +112,7 @@ namespace DBOPL RELEASE, SUSTAIN, DECAY, - ATTACK, + ATTACK } State; VolumeHandler volHandler; |