aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/adldata.cpp470
-rw-r--r--src/adlmidi.cpp245
-rw-r--r--src/adlmidi_load.cpp127
-rw-r--r--src/adlmidi_midiplay.cpp1116
-rw-r--r--src/adlmidi_opl3.cpp6
-rw-r--r--src/adlmidi_private.cpp14
-rw-r--r--src/adlmidi_private.hpp287
-rw-r--r--src/dbopl.cpp9
-rw-r--r--src/dbopl.h8
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;