XMidiFile.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003  The Pentagram Team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 #include "XMidiFile.h"
00021 #include "XMidiEvent.h"
00022 #include "XMidiEventList.h"
00023 #include "XMidiNoteStack.h"
00024 
00025 #ifdef PENTAGRAM_IN_EXULT
00026 #include "game.h"
00027 #include "databuf.h"
00028 #else
00029 #include "IDataSource.h"
00030 #include "ODataSource.h"
00031 #endif
00032 
00033 #ifndef UNDER_CE
00034 using std::atof;
00035 using std::atoi;
00036 using std::memcmp;
00037 using std::memcpy;
00038 using std::memset;
00039 using std::size_t;
00040 #endif
00041 using std::string;
00042 using std::endl;
00043 
00044 #ifndef UNDER_CE
00045 #define XMidiEvent__Malloc XMidiEvent::Malloc
00046 #define XMidiEvent__Calloc XMidiEvent::Calloc
00047 #else
00048 
00049 template<class T>
00050 static inline T* XMidiEvent__Malloc(size_t num=1)
00051 {
00052         return static_cast<T*>(std::malloc(num));
00053 }
00054 
00055 template<class T>
00056 static inline T* XMidiEvent__Calloc(size_t num=1,size_t sz=0)
00057 {
00058         if(!sz) sz=sizeof(T);
00059         return static_cast<T*>(std::calloc(num,sz));
00060 }
00061 
00062 #endif
00063 
00064 //#include "gamma.h"
00065 
00066 // This is used to correct incorrect patch, vol and pan changes in midi files
00067 // The bias is just a value to used to work out if a vol and pan belong with a 
00068 // patch change. This is to ensure that the default state of a midi file is with
00069 // the tracks centred, unless the first patch change says otherwise.
00070 #define PATCH_VOL_PAN_BIAS      5
00071 
00072 
00073 // This is a default set of patches to convert from MT32 to GM
00074 // The index is the MT32 Patch nubmer and the value is the GM Patch
00075 // This is only suitable for music that doesn'tdo timbre changes
00076 // XMidis that contain Timbre changes will not convert properly
00077 const char XMidiFile::mt32asgm[128] = {
00078         0,      // 0    Piano 1
00079         1,      // 1    Piano 2
00080         2,      // 2    Piano 3 (synth)
00081         4,      // 3    EPiano 1
00082         4,      // 4    EPiano 2
00083         5,      // 5    EPiano 3
00084         5,      // 6    EPiano 4
00085         3,      // 7    Honkytonk
00086         16,     // 8    Organ 1
00087         17,     // 9    Organ 2
00088         18,     // 10   Organ 3
00089         16,     // 11   Organ 4
00090         19,     // 12   Pipe Organ 1
00091         19,     // 13   Pipe Organ 2
00092         19,     // 14   Pipe Organ 3
00093         21,     // 15   Accordion
00094         6,      // 16   Harpsichord 1
00095         6,      // 17   Harpsichord 2
00096         6,      // 18   Harpsichord 3
00097         7,      // 19   Clavinet 1
00098         7,      // 20   Clavinet 2
00099         7,      // 21   Clavinet 3
00100         8,      // 22   Celesta 1
00101         8,      // 23   Celesta 2
00102         62,     // 24   Synthbrass 1 (62)
00103         63,     // 25   Synthbrass 2 (63)
00104         62,     // 26   Synthbrass 3 Bank 8
00105         63,     // 27   Synthbrass 4 Bank 8
00106         38,     // 28   Synthbass 1
00107         39,     // 29   Synthbass 2
00108         38,     // 30   Synthbass 3 Bank 8
00109         39,     // 31   Synthbass 4 Bank 8
00110         88,     // 32   Fantasy
00111         90,     // 33   Harmonic Pan - No equiv closest is polysynth(90) :(
00112         52,     // 34   Choral ?? Currently set to SynthVox(54). Should it be ChoirAhhs(52)???
00113         92,     // 35   Glass
00114         97,     // 36   Soundtrack
00115         99,     // 37   Atmosphere
00116         14,     // 38   Warmbell, sounds kind of like crystal(98) perhaps Tubular Bells(14) would be better. It is!
00117         54,     // 39   FunnyVox, sounds alot like Bagpipe(109) and Shania(111)
00118         98,     // 40   EchoBell, no real equiv, sounds like Crystal(98)
00119         96,     // 41   IceRain
00120         68,     // 42   Oboe 2001, no equiv, just patching it to normal oboe(68)
00121         95,     // 43   EchoPans, no equiv, setting to SweepPad
00122         81,     // 44   DoctorSolo Bank 8
00123         87,     // 45   SchoolDaze, no real equiv
00124         112,    // 46   Bell Singer
00125         80,     // 47   SquareWave
00126         48,     // 48   Strings 1
00127         48,     // 49   Strings 2 - should be 49
00128         44,     // 50   Strings 3 (Synth) - Experimental set to Tremollo Strings - should be 50
00129         45,     // 51   Pizzicato Strings
00130         40,     // 52   Violin 1
00131         40,     // 53   Violin 2 ? Viola
00132         42,     // 54   Cello 1
00133         42,     // 55   Cello 2
00134         43,     // 56   Contrabass
00135         46,     // 57   Harp 1
00136         46,     // 58   Harp 2
00137         24,     // 59   Guitar 1 (Nylon)
00138         25,     // 60   Guitar 2 (Steel)
00139         26,     // 61   Elec Guitar 1
00140         27,     // 62   Elec Guitar 2
00141         104,    // 63   Sitar
00142         32,     // 64   Acou Bass 1
00143         32,     // 65   Acou Bass 2
00144         33,     // 66   Elec Bass 1
00145         34,     // 67   Elec Bass 2
00146         36,     // 68   Slap Bass 1
00147         37,     // 69   Slap Bass 2
00148         35,     // 70   Fretless Bass 1
00149         35,     // 71   Fretless Bass 2
00150         73,     // 72   Flute 1
00151         73,     // 73   Flute 2
00152         72,     // 74   Piccolo 1
00153         72,     // 75   Piccolo 2
00154         74,     // 76   Recorder
00155         75,     // 77   Pan Pipes
00156         64,     // 78   Sax 1
00157         65,     // 79   Sax 2
00158         66,     // 80   Sax 3
00159         67,     // 81   Sax 4
00160         71,     // 82   Clarinet 1
00161         71,     // 83   Clarinet 2
00162         68,     // 84   Oboe
00163         69,     // 85   English Horn (Cor Anglais)
00164         70,     // 86   Bassoon
00165         22,     // 87   Harmonica
00166         56,     // 88   Trumpet 1
00167         56,     // 89   Trumpet 2
00168         57,     // 90   Trombone 1
00169         57,     // 91   Trombone 2
00170         60,     // 92   French Horn 1
00171         60,     // 93   French Horn 2
00172         58,     // 94   Tuba    
00173         61,     // 95   Brass Section 1
00174         61,     // 96   Brass Section 2
00175         11,     // 97   Vibes 1
00176         11,     // 98   Vibes 2
00177         99,     // 99   Syn Mallet Bank 1
00178         112,    // 100  WindBell no real equiv Set to TinkleBell(112)
00179         9,      // 101  Glockenspiel
00180         14,     // 102  Tubular Bells
00181         13,     // 103  Xylophone
00182         12,     // 104  Marimba
00183         107,    // 105  Koto
00184         111,    // 106  Sho?? set to Shanai(111)
00185         77,     // 107  Shakauhachi
00186         78,     // 108  Whistle 1
00187         78,     // 109  Whistle 2
00188         76,     // 110  Bottle Blow
00189         76,     // 111  Breathpipe no real equiv set to bottle blow(76)
00190         47,     // 112  Timpani
00191         117,    // 113  Melodic Tom
00192         116,    // 114  Deap Snare no equiv, set to Taiko(116)
00193         118,    // 115  Electric Perc 1
00194         118,    // 116  Electric Perc 2
00195         116,    // 117  Taiko
00196         115,    // 118  Taiko Rim, no real equiv, set to Woodblock(115)
00197         119,    // 119  Cymbal, no real equiv, set to reverse cymbal(119)
00198         115,    // 120  Castanets, no real equiv, in GM set to Woodblock(115)
00199         112,    // 121  Triangle, no real equiv, set to TinkleBell(112)
00200         55,     // 122  Orchestral Hit
00201         124,    // 123  Telephone
00202         123,    // 124  BirdTweet
00203         94,     // 125  Big Notes Pad no equiv, set to halo pad (94)
00204         98,     // 126  Water Bell set to Crystal Pad(98)
00205         121     // 127  Jungle Tune set to Breath Noise
00206 };
00207 
00208 // Same as above, except include patch changes
00209 // so GS instruments can be used
00210 const char XMidiFile::mt32asgs[256] = {
00211         0, 0,   // 0    Piano 1
00212         1, 0,   // 1    Piano 2
00213         2, 0,   // 2    Piano 3 (synth)
00214         4, 0,   // 3    EPiano 1
00215         4, 0,   // 4    EPiano 2
00216         5, 0,   // 5    EPiano 3
00217         5, 0,   // 6    EPiano 4
00218         3, 0,   // 7    Honkytonk
00219         16, 0,  // 8    Organ 1
00220         17, 0,  // 9    Organ 2
00221         18, 0,  // 10   Organ 3
00222         16, 0,  // 11   Organ 4
00223         19, 0,  // 12   Pipe Organ 1
00224         19, 0,  // 13   Pipe Organ 2
00225         19, 0,  // 14   Pipe Organ 3
00226         21, 0,  // 15   Accordion
00227         6, 0,   // 16   Harpsichord 1
00228         6, 0,   // 17   Harpsichord 2
00229         6, 0,   // 18   Harpsichord 3
00230         7, 0,   // 19   Clavinet 1
00231         7, 0,   // 20   Clavinet 2
00232         7, 0,   // 21   Clavinet 3
00233         8, 0,   // 22   Celesta 1
00234         8, 0,   // 23   Celesta 2
00235         62, 0,  // 24   Synthbrass 1 (62)
00236         63, 0,  // 25   Synthbrass 2 (63)
00237         62, 0,  // 26   Synthbrass 3 Bank 8
00238         63, 0,  // 27   Synthbrass 4 Bank 8
00239         38, 0,  // 28   Synthbass 1
00240         39, 0,  // 29   Synthbass 2
00241         38, 0,  // 30   Synthbass 3 Bank 8
00242         39, 0,  // 31   Synthbass 4 Bank 8
00243         88, 0,  // 32   Fantasy
00244         90, 0,  // 33   Harmonic Pan - No equiv closest is polysynth(90) :(
00245         52, 0,  // 34   Choral ?? Currently set to SynthVox(54). Should it be ChoirAhhs(52)???
00246         92, 0,  // 35   Glass
00247         97, 0,  // 36   Soundtrack
00248         99, 0,  // 37   Atmosphere
00249         14, 0,  // 38   Warmbell, sounds kind of like crystal(98) perhaps Tubular Bells(14) would be better. It is!
00250         54, 0,  // 39   FunnyVox, sounds alot like Bagpipe(109) and Shania(111)
00251         98, 0,  // 40   EchoBell, no real equiv, sounds like Crystal(98)
00252         96, 0,  // 41   IceRain
00253         68, 0,  // 42   Oboe 2001, no equiv, just patching it to normal oboe(68)
00254         95, 0,  // 43   EchoPans, no equiv, setting to SweepPad
00255         81, 0,  // 44   DoctorSolo Bank 8
00256         87, 0,  // 45   SchoolDaze, no real equiv
00257         112, 0, // 46   Bell Singer
00258         80, 0,  // 47   SquareWave
00259         48, 0,  // 48   Strings 1
00260         48, 0,  // 49   Strings 2 - should be 49
00261         44, 0,  // 50   Strings 3 (Synth) - Experimental set to Tremollo Strings - should be 50
00262         45, 0,  // 51   Pizzicato Strings
00263         40, 0,  // 52   Violin 1
00264         40, 0,  // 53   Violin 2 ? Viola
00265         42, 0,  // 54   Cello 1
00266         42, 0,  // 55   Cello 2
00267         43, 0,  // 56   Contrabass
00268         46, 0,  // 57   Harp 1
00269         46, 0,  // 58   Harp 2
00270         24, 0,  // 59   Guitar 1 (Nylon)
00271         25, 0,  // 60   Guitar 2 (Steel)
00272         26, 0,  // 61   Elec Guitar 1
00273         27, 0,  // 62   Elec Guitar 2
00274         104, 0, // 63   Sitar
00275         32, 0,  // 64   Acou Bass 1
00276         32, 0,  // 65   Acou Bass 2
00277         33, 0,  // 66   Elec Bass 1
00278         34, 0,  // 67   Elec Bass 2
00279         36, 0,  // 68   Slap Bass 1
00280         37, 0,  // 69   Slap Bass 2
00281         35, 0,  // 70   Fretless Bass 1
00282         35, 0,  // 71   Fretless Bass 2
00283         73, 0,  // 72   Flute 1
00284         73, 0,  // 73   Flute 2
00285         72, 0,  // 74   Piccolo 1
00286         72, 0,  // 75   Piccolo 2
00287         74, 0,  // 76   Recorder
00288         75, 0,  // 77   Pan Pipes
00289         64, 0,  // 78   Sax 1
00290         65, 0,  // 79   Sax 2
00291         66, 0,  // 80   Sax 3
00292         67, 0,  // 81   Sax 4
00293         71, 0,  // 82   Clarinet 1
00294         71, 0,  // 83   Clarinet 2
00295         68, 0,  // 84   Oboe
00296         69, 0,  // 85   English Horn (Cor Anglais)
00297         70, 0,  // 86   Bassoon
00298         22, 0,  // 87   Harmonica
00299         56, 0,  // 88   Trumpet 1
00300         56, 0,  // 89   Trumpet 2
00301         57, 0,  // 90   Trombone 1
00302         57, 0,  // 91   Trombone 2
00303         60, 0,  // 92   French Horn 1
00304         60, 0,  // 93   French Horn 2
00305         58, 0,  // 94   Tuba    
00306         61, 0,  // 95   Brass Section 1
00307         61, 0,  // 96   Brass Section 2
00308         11, 0,  // 97   Vibes 1
00309         11, 0,  // 98   Vibes 2
00310         99, 0,  // 99   Syn Mallet Bank 1
00311         112, 0, // 100  WindBell no real equiv Set to TinkleBell(112)
00312         9, 0,   // 101  Glockenspiel
00313         14, 0,  // 102  Tubular Bells
00314         13, 0,  // 103  Xylophone
00315         12, 0,  // 104  Marimba
00316         107, 0, // 105  Koto
00317         111, 0, // 106  Sho?? set to Shanai(111)
00318         77, 0,  // 107  Shakauhachi
00319         78, 0,  // 108  Whistle 1
00320         78, 0,  // 109  Whistle 2
00321         76, 0,  // 110  Bottle Blow
00322         76, 0,  // 111  Breathpipe no real equiv set to bottle blow(76)
00323         47, 0,  // 112  Timpani
00324         117, 0, // 113  Melodic Tom
00325         116, 0, // 114  Deap Snare no equiv, set to Taiko(116)
00326         118, 0, // 115  Electric Perc 1
00327         118, 0, // 116  Electric Perc 2
00328         116, 0, // 117  Taiko
00329         115, 0, // 118  Taiko Rim, no real equiv, set to Woodblock(115)
00330         119, 0, // 119  Cymbal, no real equiv, set to reverse cymbal(119)
00331         115, 0, // 120  Castanets, no real equiv, in GM set to Woodblock(115)
00332         112, 0, // 121  Triangle, no real equiv, set to TinkleBell(112)
00333         55, 0,  // 122  Orchestral Hit
00334         124, 0, // 123  Telephone
00335         123, 0, // 124  BirdTweet
00336         94, 0,  // 125  Big Notes Pad no equiv, set to halo pad (94)
00337         98, 0,  // 126  Water Bell set to Crystal Pad(98)
00338         121, 0  // 127  Jungle Tune set to Breath Noise
00339 };
00340 
00341 // Reverse mapping. GM Notes converted to MT-32 patches
00342 const char XMidiFile::gmasmt32[128] =
00343 {
00344         0x00, 0x01, 0x03, 0x07, 0x05, 0x06, 0x11, 0x15,
00345         0x16, 0x65, 0x65, 0x62, 0x68, 0x67, 0x66, 0x69,
00346 
00347         0x0C, 0x09, 0x0A, 0x0D, 0x0E, 0x0F, 0x57, 0x0F,
00348         0x3B, 0x3C, 0x3B, 0x3E, 0x3D, 0x3B, 0x3E, 0x3E,
00349 
00350         0x40, 0x43, 0x42, 0x47, 0x44, 0x45, 0x42 , 0x46,
00351         0x35, 0x34, 0x36, 0x38, 0x35, 0x33, 0x39 , 0x70,
00352 
00353         0X30, 0x32, 0x30, 0x32, 0x22, 0x2A, 0x21, 0x7A,
00354         0X58, 0x5A, 0x5E, 0x59, 0x5C, 0x5F, 0x59, 0x5B,
00355 
00356         0x4E, 0x4F, 0x50, 0x51, 0x54, 0x55, 0x56, 0x53,
00357         0x4B, 0x49, 0x4C, 0x4D, 0x6E, 0x6B, 0x6C, 0x48,
00358 
00359         0x2F, 0x43, 0x4B, 0x33, 0x3D, 0x48, 0x34, 0x43,
00360         0x20, 0x21, 0x43, 0x22, 0x20, 0x20, 0x21, 0x21,
00361 
00362         0x29, 0x24, 0x23, 0x25, 0x2D, 0x21, 0x2B, 0x20,
00363         0x3F, 0x69, 0x69, 0x69, 0x33, 0x51, 0x34, 0x51,
00364 
00365         0x17, 0x67, 0x67, 0x71, 0x75, 0x71, 0x74, 0x77,
00366         0x7C, 0x78, 0x77, 0x7C, 0x7B, 0x78, 0x77, 0x72
00367 };
00368 
00369 //
00370 // MT32 SysEx
00371 //
00372 static const uint32 sysex_data_start = 7;               // Data starts at byte 7
00373 static const uint32 sysex_max_data_size = 256;
00374 
00375 
00376 //
00377 // Percussion
00378 //
00379 
00380 static const uint32 rhythm_base = 0x030110;     // Note, these are 7 bit!
00381 static const uint32 rhythm_mem_size = 4;
00382 
00383 static const uint32 rhythm_first_note = 24;
00384 static const uint32 rhythm_num_notes = 64;
00385 
00386 // Memory offset based on index in the table
00387 static inline uint32 rhythm_mem_offset(uint32 index_num) { 
00388         return index_num * 4; 
00389 }
00390 
00391 // Memory offset based on note key num
00392 static inline uint32 rhythm_mem_offset_note(uint32 rhythm_note_num) { 
00393         return (rhythm_note_num-rhythm_first_note) * 4; 
00394 }
00395 
00396 struct RhythmSetupData {
00397         uint8           timbre;                                 // 0-94 (M1-M64,R1-30,OFF)
00398         uint8           output_level;                   // 0-100
00399         uint8           panpot;                                 // 0-14 (L-R)
00400         uint8           reverb_switch;                  // 0-1 (off,on)
00401 };
00402 
00403 
00404 //
00405 // Timbre Memory Consts
00406 //
00407 static const uint32 timbre_base = 0x080000;     // Note, these are 7 bit!
00408 static const uint32 timbre_mem_size = 246;
00409 static inline uint32 timbre_mem_offset(uint32 timbre_num) { return timbre_num * 256; }
00410 
00411 
00412 //
00413 // Patch Memory Consts
00414 //
00415 static const uint32 patch_base = 0x050000;              // Note, these are 7 bit!
00416 static const uint32 patch_mem_size = 8;
00417 static inline uint32 patch_mem_offset(uint32 patch_num) { return patch_num * 8; }
00418 
00419 struct PatchMemData {
00420         uint8           timbre_group;                   // 0-3  (group A, group B, Memory, Rhythm)
00421         uint8           timbre_num;                             // 0-63
00422         uint8           key_shift;                              // 0-48
00423         uint8           fine_tune;                              // 0-100 (-50 - +50)
00424         uint8           bender_range;                   // 0-24
00425         uint8           assign_mode;                    // 0-3 (POLY1, POLY2, POLY3, POLY4)
00426         uint8           reverb_switch;                  // 0-1 (off,on)
00427         uint8           dummy;
00428 };
00429 
00430 static const PatchMemData patch_template = {
00431         2,              // timbre_group
00432         0,              // timbre_num
00433         24,             // key_shift
00434         50,             // fine_tune
00435         24,             // bender_range
00436         0,              // assign_mode
00437         1,              // reverb_switch
00438         0               // dummy
00439 };
00440         
00441 
00442 //
00443 // System Area Consts
00444 //
00445 static const uint32 system_base = 0x100000;     // Note, these are 7 bit!
00446 static const uint32 system_mem_size = 0x17;     // Display is 20 ASCII characters (32-127)
00447 #define system_mem_offset(setting) ((uintptr)(&((systemArea*)0)->setting))
00448 
00449 struct systemArea {
00450         char masterTune;                                        // MASTER TUNE 0-127 432.1-457.6Hz
00451         char reverbMode;                                        // REVERB MODE 0-3 (room, hall, plate, tap delay)
00452         char reverbTime;                                        // REVERB TIME 0-7 (1-8)
00453         char reverbLevel;                                       // REVERB LEVEL 0-7 (1-8)
00454         char reserveSettings[9];                        // PARTIAL RESERVE (PART 1) 0-32
00455         char chanAssign[9];                                     // MIDI CHANNEL (PART1) 0-16 (1-16,OFF)
00456         char masterVol;                                         // MASTER VOLUME 0-100
00457 };
00458 
00459 static const char system_init_reverb[3] = { 0,3,2 };                            // reverb mode = 0, time = 3, level = 2
00460 static const char system_part_chans[9] =  { 1,2,3,4,5,6,7,8,9 };        // default (0-based) chans for each part
00461 static const char system_part_rsv[9] = { 3,4,3,4,3,4,3,4,4 };           // # of reserved AIL partials/channel
00462 
00463 //
00464 // Display  Consts
00465 //
00466 static const uint32 display_base = 0x200000;    // Note, these are 7 bit!
00467 static const uint32 display_mem_size = 0x14;    // Display is 20 ASCII characters (32-127)
00468 
00469 // Display messages                         0123456789ABCDEF0123
00470 #ifdef PENTAGRAM_IN_EXULT
00471 static const char display[]              = " Uploading Timbres! ";
00472 static const char display_black_gate[]   = "BG Uploading Timbres";
00473 static const char display_serpent_isle[] = "SI Uploading Timbres";
00474 
00475 static const char display_beginning[] =    "--==|  Exult!  |==--";
00476 static const char display_beginning_bg[] = " U7: The Black Gate ";
00477 static const char display_beginning_si[] = "U7: The Serpent Isle";
00478 #else
00479 
00480 static const char display[]              = " Uploading Timbres! ";
00481 static const char display_beginning[] =    "--=| Pentagram! |=--";
00482 #endif
00483 
00484 //
00485 // All Dev Reset
00486 //
00487 static const uint32 all_dev_reset_base = 0x7f0000;
00488 
00489 
00490 //
00491 // U7 Percussion Table
00492 //
00493 // Why this crap wasn't in the flexes i will never know
00494 //
00495 
00496 // The key num that the data below belongs to (subtract 24 to get memory num)
00497 static uint8 U7PercussionNotes[] = {
00498         28, 33, 74, 76, 77, 78, 79, 80,
00499         81, 82, 83, 84, 85, 86, 87, 0
00500 };
00501 
00502 // The RhythmSetup data 
00503 static RhythmSetupData U7PercussionData[] = {
00504         {       0,      0x5A,   0x07,   0       },      // 28
00505         {       6,      0x64,   0x07,   1       },      // 33
00506         {       1,      0x5A,   0x05,   0       },      // 74
00507         {       1,      0x5A,   0x06,   0       },      // 76
00508         {       1,      0x5A,   0x07,   0       },      // 77
00509         {       2,      0x64,   0x07,   1       },      // 78
00510         {       1,      0x5A,   0x08,   0       },      // 79
00511         {       5,      0x5A,   0x07,   1       },      // 80
00512         {       1,      0x5A,   0x09,   0       },      // 81
00513         {       3,      0x5F,   0x07,   1       },      // 82
00514         {       4,      0x64,   0x04,   1       },      // 83
00515         {       4,      0x64,   0x05,   1       },      // 84
00516         {       4,      0x64,   0x06,   1       },      // 85
00517         {       4,      0x64,   0x07,   1       },      // 86
00518         {       4,      0x64,   0x08,   1       }       // 87
00519 };
00520 
00521 //GammaTable<unsigned char> XMidiFile::VolumeCurve(128);
00522 
00523 // Constructor
00524 XMidiFile::XMidiFile(IDataSource *source, int pconvert) : num_tracks(0),
00525                                                 events(NULL), convert_type(pconvert),
00526                                                 do_reverb(false), do_chorus(false)
00527 {
00528         std::memset(bank127,0,sizeof(bank127));
00529         
00530         ExtractTracks (source);
00531 
00532         // SysEx data
00533         if (pconvert >= XMIDIFILE_HINT_U7VOICE_MT_FILE) InsertDisplayEvents();
00534 }
00535 
00536 XMidiFile::~XMidiFile()
00537 {
00538         if (events)
00539         {
00540                 for (int i=0; i < num_tracks; i++) {
00541                         events[i]->decerementCounter();
00542                         events[i] = NULL;
00543                 }
00544                 //delete [] events;
00545                 XMidiEvent::Free(events);
00546         }
00547 }
00548 
00549 XMidiEventList *XMidiFile::GetEventList (uint32 track)
00550 {
00551         if (!events)
00552         {
00553                 perr << "No midi data in loaded." << endl;
00554                 return 0;
00555         }
00556 
00557         if (track >= num_tracks)
00558         {
00559                 perr << "Can't retrieve MIDI data, track out of range" << endl;
00560                 return 0;
00561         }
00562 
00563         return events[track];
00564 }
00565 
00566 // Sets current to the new event and updates list
00567 void XMidiFile::CreateNewEvent (int time)
00568 {
00569         if (!list)
00570         {
00571                 list = current = XMidiEvent__Calloc<XMidiEvent>();
00572                 if (time > 0)
00573                         current->time = time;
00574                 return;
00575         }
00576 
00577         if (time < 0 || list->time > time)
00578         {
00579                 XMidiEvent *event = XMidiEvent__Calloc<XMidiEvent>();
00580                 event->next = list;
00581                 list = current = event;
00582                 return;
00583         }
00584 
00585         if (!current || current->time > time)
00586                 current = list;
00587 
00588         while (current->next)
00589         {
00590                 if (current->next->time > time)
00591                 {
00592                         XMidiEvent *event = XMidiEvent__Calloc<XMidiEvent>();
00593                         
00594                         event->next = current->next;
00595                         current->next = event;
00596                         current = event;
00597                         current->time = time;
00598                         return;
00599                 }
00600                 
00601                 current = current->next;
00602         }
00603 
00604         current->next = XMidiEvent__Calloc<XMidiEvent>();
00605         current = current->next;
00606         current->time = time;
00607 }
00608 
00609 //
00610 // GetVLQ
00611 //
00612 // Get a Conventional Variable Length Quantity
00613 //
00614 int XMidiFile::GetVLQ (IDataSource *source, uint32 &quant)
00615 {
00616         int i;
00617         quant = 0;
00618         unsigned int data;
00619 
00620         for (i = 0; i < 4; i++)
00621         {
00622                 data = source->read1();
00623                 quant <<= 7;
00624                 quant |= data & 0x7F;
00625 
00626                 if (!(data & 0x80))
00627                 {
00628                         i++;
00629                         break;
00630                 }
00631 
00632         }
00633         return i;
00634 }
00635 
00636 //
00637 // GetVLQ2
00638 //
00639 // Get a XMidiFile Variable Length Quantity
00640 //
00641 int XMidiFile::GetVLQ2 (IDataSource *source, uint32 &quant)
00642 {
00643         int i;
00644         quant = 0;
00645         int data = 0;
00646         
00647         for (i = 0; i < 4; i++)
00648         {
00649                 data = source->read1();
00650                 if (data & 0x80)
00651                 {
00652                         source->skip(-1);
00653                         break;
00654                 }
00655                 quant += data;
00656         }
00657         return i;
00658 }
00659 
00660 //
00661 // MovePatchVolAndPan.
00662 //
00663 // Well, this is just a modified version of what that method used to do. This
00664 // is a massive optimization. Speed up should be quite impressive
00665 //
00666 void XMidiFile::ApplyFirstState(first_state &fs, int chan_mask)
00667 {
00668         for (int channel = 0; channel < 16; channel++)
00669         {
00670                 XMidiEvent *patch = fs.patch[channel];
00671                 XMidiEvent *vol = fs.vol[channel];
00672                 XMidiEvent *pan = fs.pan[channel];
00673                 XMidiEvent *bank = fs.bank[channel];
00674                 XMidiEvent *reverb = NULL;
00675                 XMidiEvent *chorus = NULL;
00676                 XMidiEvent *temp;
00677 
00678                 // Got no patch change, return and don't try fixing it
00679                 if (!patch || !(chan_mask & 1 << channel)) continue;
00680 #if 0
00681                 std::cout << "Channel: " << channel+1 << std::endl;
00682                 std::cout << "Patch: " << (unsigned int) patch->data[0] << " @ " << patch->time << std::endl;
00683                 if (bank) std::cout << " Bank: " << (unsigned int) bank->data[1] << " @ " << bank->time << std::endl;
00684                 if (vol) std::cout << "  Vol: " << (unsigned int) vol->data[1] << " @ " << vol->time << std::endl;
00685                 if (pan) std::cout << "  Pan: " << ((signed int) pan->data[1])-64 << " @ " << pan->time << std::endl;
00686                 std::cout << std::endl;
00687 #endif
00688 
00689                 // Copy Patch Change Event
00690                 temp = patch;
00691                 patch = XMidiEvent__Calloc<XMidiEvent>();
00692                 patch->time = temp->time;
00693                 patch->status = channel|(MIDI_STATUS_PROG_CHANGE << 4);
00694                 patch->data[0] = temp->data[0];
00695 
00696                 // Copy Volume
00697                 if (vol && (vol->time > patch->time+PATCH_VOL_PAN_BIAS || vol->time < patch->time-PATCH_VOL_PAN_BIAS))
00698                         vol = NULL;
00699 
00700                 temp = vol;
00701                 vol = XMidiEvent__Calloc<XMidiEvent>();
00702                 vol->status = channel|(MIDI_STATUS_CONTROLLER << 4);
00703                 vol->data[0] = 7;
00704 
00705                 if (!temp)
00706                 {
00707 //                      if (convert_type) vol->data[1] = VolumeCurve[90];
00708                         if (convert_type) vol->data[1] = 90;
00709                         else vol->data[1] = 90;
00710                 }
00711                 else
00712                         vol->data[1] = temp->data[1];
00713 
00714 
00715                 // Copy Bank
00716                 if (bank && (bank->time > patch->time+PATCH_VOL_PAN_BIAS || bank->time < patch->time-PATCH_VOL_PAN_BIAS))
00717                         bank = NULL;
00718 
00719                 temp = bank;
00720                 
00721                 bank = XMidiEvent__Calloc<XMidiEvent>();
00722                 bank->status = channel|(MIDI_STATUS_CONTROLLER << 4);
00723 
00724                 if (!temp)
00725                         bank->data[1] = 0;
00726                 else
00727                         bank->data[1] = temp->data[1];
00728 
00729                 // Copy Pan
00730                 if (pan && (pan->time > patch->time+PATCH_VOL_PAN_BIAS || pan->time < patch->time-PATCH_VOL_PAN_BIAS))
00731                         pan = NULL;
00732 
00733                 temp = pan;
00734                 pan = XMidiEvent__Calloc<XMidiEvent>();
00735                 pan->status = channel|(MIDI_STATUS_CONTROLLER << 4);
00736                 pan->data[0] = 10;
00737 
00738                 if (!temp)
00739                         pan->data[1] = 64;
00740                 else
00741                         pan->data[1] = temp->data[1];
00742 
00743                 if (do_reverb)
00744                 {
00745                         reverb = XMidiEvent__Calloc<XMidiEvent>();
00746                         reverb->status = channel|(MIDI_STATUS_CONTROLLER << 4);
00747                         reverb->data[0] = 91;
00748                         reverb->data[1] = reverb_value;
00749                 }
00750 
00751                 if (do_chorus)
00752                 {
00753                         chorus = XMidiEvent__Calloc<XMidiEvent>();
00754                         chorus->status = channel|(MIDI_STATUS_CONTROLLER << 4);
00755                         chorus->data[0] = 93;
00756                         chorus->data[1] = chorus_value;
00757                 }
00758 
00759                 vol->time = 0;
00760                 pan->time = 0;
00761                 patch->time = 0;
00762                 bank->time = 0;
00763                 
00764                 if (do_reverb && do_chorus) reverb->next = chorus;
00765                 else if (do_reverb) reverb->next = bank;
00766                 if (do_chorus) chorus->next = bank;
00767                 bank->next = vol;
00768                 vol->next = pan;
00769                 pan->next = patch;
00770                 
00771                 patch->next = list;
00772                 if (do_reverb) list = reverb;
00773                 else if (do_chorus) list = chorus;
00774                 else list = bank;
00775         }
00776 }
00777 
00778 #ifndef BEOS
00779 // Unsigned 64 Bit Int emulation. Only supports SOME operations
00780 struct uint64 {
00781         uint32  low;            // Low is first so uint64 can be cast as uint32 to get low dword
00782         uint32  high;           // 
00783 
00784         uint64() : low(0), high(0) { }
00785         uint64(uint32 i) : low(i), high(0) { }
00786         uint64(uint32 h, uint32 l) : low(l), high(h) { }
00787         uint64(const uint64 &i) : low(i.low), high(i.high) { }
00788 
00789         inline void addlow(uint32 l) {
00790                 uint32 mid = (low >> 16);
00791                 low = (low & 0xFFFF) + (l & 0xFFFF);
00792                 mid += (low >> 16) + (l >> 16);
00793                 low = (low&0xFFFF) + (mid << 16);
00794                 high += mid >> 16;
00795         }
00796 
00797         // uint64 operations
00798 
00799         inline uint64 & operator = (uint64 &o) {
00800                 low = o.low;
00801                 high = o.high;
00802                 return *this;
00803         }
00804 
00805         inline uint64 & operator += (uint64 &o) {
00806                 addlow(o.low);
00807                 high += o.high;
00808                 return *this;
00809         }
00810 
00811         inline uint64 operator + (uint64 &o) {
00812                 uint64 n(*this);
00813                 n.addlow(o.low);
00814                 n.high += o.high;
00815                 return n;
00816         }
00817 
00818         // uint32 operations
00819 
00820         inline uint64 & operator = (uint32 i) {
00821                 low = i;
00822                 high = 0;
00823                 return *this;
00824         }
00825 
00826         inline uint64 & operator += (uint32 i) {
00827                 addlow(i);
00828                 return *this;
00829         }
00830 
00831         inline uint64 operator + (uint32 i) {
00832                 uint64 n(*this);
00833                 n.addlow(i);
00834                 return n;
00835         }
00836 
00837         inline uint64 & operator *= (uint32 i) {
00838                 // High 16 bits
00839                 uint32 h1 =   i >> 16;
00840                 uint32 h2 = low >> 16;
00841                 //uint32 h3 = high >> 16;
00842 
00843                 // Low 16 Bits
00844                 uint32 l1 =   i & 0xFFFF;
00845                 uint32 l2 = low & 0xFFFF;
00846                 uint32 l3 = high & 0xFFFF;
00847 
00848                 // The accumulator
00849                 uint32 accum;
00850 
00851                 // 0 -> 32
00852                 low = l1*l2;
00853                 high = 0;
00854 
00855                 // 16 -> 48
00856                 accum = h1*l2;
00857                 addlow(accum<<16);
00858                 high += accum>>16;
00859 
00860                 // 16 -> 48
00861                 accum = l1*h2;
00862                 addlow(accum<<16);      
00863                 high += accum>>16;
00864 
00865                 // 32 -> 64
00866                 high += h1*h2;
00867 
00868                 // 32 -> 64
00869                 high += l1*l3;
00870 
00871                 // 48 -> 80
00872                 high += (h1*l3) << 16;
00873 
00874                 // 48 -> 80
00875                 high += (l1*l3) << 16;
00876 
00877                 return *this;
00878         }
00879 
00880         inline uint64 operator * (uint32 i) {
00881                 uint64 n(*this);
00882                 return n*=i;
00883         }
00884 
00885         inline uint64 & operator /= (uint32 div) {
00886 
00887                 // If there isn't a high dword, we only need to work on the low dword
00888                 if (!high) {
00889                         low /= div;
00890                         return *this;
00891                 }
00892 
00893                 // modulus of last division
00894                 uint32 mod = high;
00895                 uint32 l = low;
00896 
00897                 // Low shift
00898                 uint32 shift = 32;
00899                 low = 0;
00900 
00901                 // Only High DWORD
00902                 // Can divide
00903                 if (mod >= div) {
00904                         high = mod / div;
00905                         mod %= div;
00906                 }
00907                 else high = 0;
00908 
00909                 // Only Both high and low
00910                 while (--shift) {
00911 
00912                         mod <<= 1;
00913                         mod |= (l>>shift) & 1;
00914 
00915                         // Can divide
00916                         if (mod >= div) {
00917                                 uint32 v = mod / div;
00918                                 mod %= div;
00919                                 addlow(v << shift);
00920                                 high += v >> (32 - shift);
00921                         }
00922                 }
00923 
00924 
00925                 // Only Low DWORD
00926                 mod <<= 1;
00927                 mod |= l & 1;
00928 
00929                 // Can divide
00930                 if (mod >= div) {
00931                         uint32 v = mod / div;
00932                         mod %= div;
00933                         addlow(v << shift);
00934                 }
00935 
00936                 return *this;
00937         }
00938 
00939         inline uint64 operator / (uint32 i) {
00940                 uint64 n(*this);
00941                 return n/=i;
00942         }
00943 
00944         inline uint64 & operator %= (uint32 div) {
00945 
00946                 // If there isn't a high dword, we only need to work on the low dword
00947                 if (!high) {
00948                         low %= div;
00949                         return *this;
00950                 }
00951 
00952                 // Remainder of last division
00953                 uint32 mod = high;
00954 
00955                 // Low shift
00956                 uint32 shift = 32;
00957 
00958                 while (1) {
00959 
00960                         // Can divide
00961                         if (mod >= div) mod %= div;
00962 
00963                         if (shift == 0) break;
00964 
00965                         mod <<= 1;
00966                         shift--;
00967                         mod |= (low>>shift) & 1;
00968                 }
00969 
00970                 high = 0;
00971                 low = mod;
00972 
00973                 return *this;
00974         }
00975 
00976         inline uint64 operator % (uint32 i) {
00977                 uint64 n(*this);
00978                 return n%=i;
00979         }
00980 
00981         inline operator uint32 ()
00982         {
00983                 return low;
00984         }
00985 
00986         void printx() {
00987                 if (high) std::printf ("%X%08X", high, low);
00988                 else printf ("%X", low);
00989         }
00990 };
00991 #endif
00992 
00993 //
00994 // AdjustTimings
00995 //
00996 // It converts the midi's to use 120 Hz timing, and also calcs the duration of
00997 // the notes. It also strips the tempo events, and adds it's own
00998 //
00999 // This is used by Midi's ONLY! It will do nothing with XMidiFile
01000 //
01001 void XMidiFile::AdjustTimings(uint32 ppqn)
01002 {
01003         uint32          tempo = 500000;
01004         uint32          time_prev = 0;
01005         uint32          hs_rem = 0;
01006         uint32          hs     = 0;
01007 
01008         ppqn *= 10000;
01009 
01010         // Virtual playing
01011         XMidiNoteStack notes;
01012 
01013         for (XMidiEvent *event = list; event; event = event->next) {
01014 
01015                         // Note 64 bit int is required because multiplication by tempo can
01016                         // require 52 bits in some circumstances
01017 
01018                         uint64 aim = event->time - time_prev;
01019                         aim *= tempo;
01020 
01021                         hs_rem += aim%ppqn;
01022                         hs += aim/ppqn;
01023                         hs += hs_rem/ppqn;
01024                         hs_rem %= ppqn;
01025 
01026                         time_prev = event->time;
01027                         event->time = (hs*6)/5 + (6*hs_rem)/(5*ppqn);
01028                                 
01029                         // Note on and note off handling
01030                         if (event->status <= 0x9F) {
01031 
01032                                 // Add if it's a note on and remove if it's a note off
01033                                 if ((event->status>>4) == MIDI_STATUS_NOTE_ON && event->data[1]) 
01034                                         notes.Push(event);
01035                                 else {
01036                                         XMidiEvent *prev = notes.FindAndPop(event);
01037                                         if (prev) prev->ex.note_on.duration = event->time - prev->time;
01038                                 }
01039 
01040                         }
01041                         else if (event->status == 0xFF && event->data[0] == 0x51) {
01042 
01043                                 tempo = (event->ex.sysex_data.buffer[0] << 16) +
01044                                         (event->ex.sysex_data.buffer[1] << 8) +
01045                                         event->ex.sysex_data.buffer[2];
01046                                         
01047                                 event->ex.sysex_data.buffer[0] = 0x07;
01048                                 event->ex.sysex_data.buffer[1] = 0xA1;
01049                                 event->ex.sysex_data.buffer[2] = 0x20;
01050                         }
01051         }
01052 
01053         //std::cout << "Max Polyphony: " << notes.GetMaxPolyphony() << std::endl;
01054         static const unsigned char tempo_buf[5] = { 0x51, 0x03, 0x07, 0xA1, 0x20 };
01055         IBufferDataSource ds(tempo_buf, 5);
01056         current = list;
01057         ConvertSystemMessage (0, 0xFF,&ds);
01058 }
01059 
01060 
01061 // Converts Events
01062 //
01063 // Source is at the first data byte
01064 // size 1 is single data byte (ConvertEvent Only)
01065 // size 2 is dual data byte
01066 // size 3 is XMI Note on (ConvertNote only)
01067 // Returns bytes converted
01068 //
01069 // ConvertNote is used for Note On's and Note offs
01070 // ConvertSystemMessage is used for SysEx events and Meta events
01071 // ConvertEvent is used for everything else
01072 
01073 int XMidiFile::ConvertEvent (const int time, const unsigned char status, IDataSource *source, const int size, first_state &fs)
01074 {
01075         int     data;
01076 
01077         data = source->read1();
01078 
01079 
01080         // Bank changes are handled here
01081         if ((status >> 4) == 0xB && data == 0)
01082         {
01083                 data = source->read1();
01084                 
01085                 bank127[status&0xF] = false;
01086                 
01087                 if (convert_type == XMIDIFILE_CONVERT_MT32_TO_GM 
01088                         || convert_type == XMIDIFILE_CONVERT_MT32_TO_GS
01089                         || convert_type == XMIDIFILE_CONVERT_MT32_TO_GS127)
01090                         return 2;
01091 
01092                 CreateNewEvent (time);
01093                 current->status = status;
01094                 current->data[0] = 0;
01095                 current->data[1] = data;
01096 
01097                 // Set the bank
01098                 if (!fs.bank[status&0xF] || fs.bank[status&0xF]->time > time) fs.bank[status&0xF] = current;
01099 
01100                 if (convert_type == XMIDIFILE_CONVERT_GS127_TO_GS && data == 127)
01101                         bank127[status&0xF] = true;
01102 
01103                 return 2;
01104         }
01105 
01106         // Handling for patch change mt32 conversion, probably should go elsewhere
01107         if ((status >> 4) == 0xC && (status&0xF) != 9 && convert_type != XMIDIFILE_CONVERT_NOCONVERSION)
01108         {
01109                 if (convert_type == XMIDIFILE_CONVERT_MT32_TO_GM)
01110                 {
01111                         data = mt32asgm[data];
01112                 }
01113                 else if (convert_type == XMIDIFILE_CONVERT_GM_TO_MT32)
01114                 {
01115                         data = gmasmt32[data];
01116                 }
01117                 else if ((convert_type == XMIDIFILE_CONVERT_GS127_TO_GS && bank127[status&0xF]) ||
01118                                 convert_type == XMIDIFILE_CONVERT_MT32_TO_GS)
01119                 {
01120                         CreateNewEvent (time);
01121                         current->status = 0xB0 | (status&0xF);
01122                         current->data[0] = 0;
01123                         current->data[1] = mt32asgs[data*2+1];
01124 
01125                         data = mt32asgs[data*2];
01126 
01127                         // Set the bank
01128                         if (!fs.bank[status&0xF] || fs.bank[status&0xF]->time > time) fs.bank[status&0xF] = current;
01129                 }
01130                 else if (convert_type == XMIDIFILE_CONVERT_MT32_TO_GS127)
01131                 {
01132                         CreateNewEvent (time);
01133                         current->status = 0xB0 | (status&0xF);
01134                         current->data[0] = 0;
01135                         current->data[1] = 127;
01136 
01137                         // Set the bank
01138                         if (!fs.bank[status&0xF] || fs.bank[status&0xF]->time > time) fs.bank[status&0xF] = current;
01139                 }
01140         }// Disable patch changes on Track 10 is doing a conversion
01141         else if ((status >> 4) == 0xC && (status&0xF) == 9 && convert_type != XMIDIFILE_CONVERT_NOCONVERSION)
01142         {
01143                 return size;
01144         }
01145 
01146         CreateNewEvent (time);
01147         current->status = status;
01148 
01149         current->data[0] = data;
01150 
01151         // Check for patch change, and update fs if req
01152         if ((status >> 4) == 0xC) {
01153                 if (!fs.patch[status&0xF] || fs.patch[status&0xF]->time > time)
01154                         fs.patch[status&0xF] = current;
01155         }
01156         // Controllers
01157         else if ((status >> 4) == 0xB) {
01158                 // Volume
01159                 if (current->data[0] == 7) {
01160                         if (!fs.vol[status&0xF] || fs.vol[status&0xF]->time > time)
01161                                 fs.vol[status&0xF] = current;
01162                 }
01163                 // Pan
01164                 else if (current->data[0] == 10) {
01165                         if (!fs.pan[status&0xF] || fs.pan[status&0xF]->time > time)
01166                                 fs.pan[status&0xF] = current;
01167                 }
01168                 // Sequence Branch Index
01169                 else if (current->data[0] == XMIDI_CONTROLLER_SEQ_BRANCH_INDEX) {
01170                         current->ex.branch_index.next_branch = branches;
01171                         branches = current;
01172                 }
01173         }
01174 
01175         if (size == 1)
01176                 return 1;
01177 
01178         current->data[1] = source->read1();
01179 
01180         // Volume modify the volume controller, only if converting
01181 //      if (convert_type && (current->status >> 4) == MIDI_STATUS_CONTROLLER && current->data[0] == 7)
01182 //              current->data[1] = VolumeCurve[current->data[1]];
01183 
01184         return 2;
01185 }
01186 
01187 int XMidiFile::ConvertNote (const int time, const unsigned char status, IDataSource *source, const int size)
01188 {
01189         uint32  delta = 0;
01190         int     data;
01191 
01192         data = source->read1();
01193 
01194         CreateNewEvent (time);
01195         current->status = status;
01196 
01197         current->data[0] = data;
01198         current->data[1] = source->read1();
01199 
01200         // Volume modify the note on's, only if converting
01201 //      if (convert_type && (current->status >> 4) == MIDI_STATUS_NOTE_ON && current->data[1])
01202 //              current->data[1] = VolumeCurve[current->data[1]];
01203 
01204         if (size == 2)
01205                 return 2;
01206 
01207         // XMI Note On handling
01208 
01209         // Get the duration
01210         int i = GetVLQ (source, delta);
01211         
01212         // Set the duration
01213         current->ex.note_on.duration = delta;
01214 
01215         // This is an optimization
01216         XMidiEvent *prev = current;
01217                 
01218         // Create a note off
01219         CreateNewEvent (time+delta);
01220 
01221         current->status = status;
01222         current->data[0] = data;
01223         current->data[1] = 0;
01224         
01225         // Optimization
01226         current = prev;
01227 
01228         return i + 2;
01229 }
01230 
01231 // Simple routine to convert system messages
01232 int XMidiFile::ConvertSystemMessage (const int time, const unsigned char status, IDataSource *source)
01233 {
01234         int i=0;
01235         
01236         CreateNewEvent (time);
01237         current->status = status;
01238         
01239         // Handling of Meta events
01240         if (status == 0xFF)
01241         {
01242                 current->data[0] = source->read1();
01243                 i++;    
01244         }
01245 
01246         i += GetVLQ (source, current->ex.sysex_data.len);
01247 
01248         if (!current->ex.sysex_data.len)
01249         {
01250                 current->ex.sysex_data.buffer = NULL;
01251                 return i;
01252         }
01253         
01254         current->ex.sysex_data.buffer = XMidiEvent__Malloc<unsigned char>(current->ex.sysex_data.len);
01255 
01256         source->read (reinterpret_cast<char *>(current->ex.sysex_data.buffer), current->ex.sysex_data.len);
01257 
01258         return i+current->ex.sysex_data.len;
01259 }
01260 
01261 // If data is NULL, then it is assumed that sysex_buffer already contains the data
01262 // address_base is 7-bit, while address_offset is 8 bit!
01263 int XMidiFile::CreateMT32SystemMessage(const int time, uint32 address_base, uint16 address_offset, uint32 len, const void *data, IDataSource *source)
01264 {
01265         CreateNewEvent (time);
01266         // SysEx status
01267         current->status = 0xF0;
01268 
01269         // Allocate the buffer
01270         current->ex.sysex_data.len = sysex_data_start+len+2;
01271         unsigned char *sysex_buffer = current->ex.sysex_data.buffer = 
01272                         XMidiEvent__Malloc<unsigned char>(current->ex.sysex_data.len);
01273 
01274         // MT32 Sysex Header
01275         sysex_buffer[0] = 0x41;         // Roland SysEx ID
01276         sysex_buffer[1] = 0x10;         // Device ID (assume 0x10, Device 17)
01277         sysex_buffer[2] = 0x16;         // MT-32 Model ID
01278         sysex_buffer[3] = 0x12;         // DTI Command ID (set data)
01279 
01280         // 7-bit address
01281         uint32 actual_address = address_offset;
01282         actual_address += (address_base>>2) & (0x7f<<14);
01283         actual_address += (address_base>>1) & (0x7f<<7);
01284         actual_address += (address_base>>0) & (0x7f<<0);
01285         sysex_buffer[4] = (actual_address>>14)&0x7F;
01286         sysex_buffer[5] = (actual_address>>7)&0x7F;
01287         sysex_buffer[6] = actual_address&0x7F;
01288 
01289         // Only copy if required
01290         if (data) std::memcpy (sysex_buffer+sysex_data_start, data, len);
01291         else if (source) source->read(sysex_buffer+sysex_data_start,len);
01292 
01293         // Calc checksum
01294         char checksum = 0;
01295         for (uint32 j = 4; j < sysex_data_start+len; j++)
01296                 checksum += sysex_buffer[j];
01297 
01298         checksum = checksum & 0x7f;
01299         if (checksum) checksum = 0x80 - checksum;
01300 
01301         // Set checksum
01302         sysex_buffer[sysex_data_start+len] = checksum;
01303 
01304         // Terminator
01305         sysex_buffer[sysex_data_start+len+1] = 0xF7;
01306 
01307         return sysex_data_start+len+2;
01308 }
01309 
01310 // XMidiFile and Midi to List. Returns bit mask of channels used
01311 int XMidiFile::ConvertFiletoList (IDataSource *source, const bool is_xmi, first_state &fs)
01312 {
01313         int     time = 0;                       // 120th of a second
01314         uint32  data;
01315         int             end = 0;
01316         uint32  status = 0;
01317         int             play_size = 2;
01318         uint32  file_size = source->getSize();
01319         int             retval = 0;
01320 
01321         if (is_xmi) play_size = 3;
01322 
01323         while (!end && source->getPos() < file_size)
01324         {
01325                 if (!is_xmi)
01326                 {
01327                         GetVLQ (source, data);
01328                         time += data;
01329 
01330                         data = source->read1();
01331                 
01332                         if (data >= 0x80)
01333                         {
01334                                 status = data;
01335                         }
01336                         else
01337                                 source->skip (-1);
01338                 }       
01339                 else
01340                 {
01341                         GetVLQ2 (source, data);
01342                         time += data;
01343 
01344                         status = source->read1();
01345                 }
01346 
01347                 switch (status >> 4)
01348                 {
01349                         case MIDI_STATUS_NOTE_ON:
01350                         retval |= 1 << (status & 0xF);
01351                         ConvertNote (time, status, source, play_size);
01352                         break;
01353 
01354                         case MIDI_STATUS_NOTE_OFF:
01355                         ConvertNote (time, status, source, 2);
01356                         break;
01357 
01358                         // 2 byte data
01359                         case MIDI_STATUS_AFTERTOUCH:
01360                         case MIDI_STATUS_CONTROLLER:
01361                         case MIDI_STATUS_PITCH_WHEEL:
01362                         ConvertEvent (time, status, source, 2, fs);
01363                         break;
01364                         
01365 
01366                         // 1 byte data
01367                         case MIDI_STATUS_PROG_CHANGE:
01368                         case MIDI_STATUS_PRESSURE:
01369                         ConvertEvent (time, status, source, 1, fs);
01370                         break;
01371                         
01372 
01373                         case MIDI_STATUS_SYSEX:
01374                         if (status == 0xFF)
01375                         {
01376                                 int     pos = source->getPos();
01377                                 uint32  data = source->read1();
01378                                 
01379                                 if (data == 0x2F)                                       // End, of track
01380                                         end = 1;
01381                                 else if (data == 0x51 && is_xmi)        // XMidiFile doesn't use tempo
01382                                 {
01383                                         GetVLQ (source, data);
01384                                         source->skip(data);
01385                                         break;
01386                                 }
01387                                 
01388                                 source->seek (pos);
01389                         }
01390                         ConvertSystemMessage (time, status, source);
01391                         break;
01392 
01393                         default:
01394                         break;
01395                 }
01396 
01397         }
01398 
01399         return retval;
01400 }
01401 
01402 // Assumes correct XMidiFile
01403 int XMidiFile::ExtractTracksFromXmi (IDataSource *source)
01404 {
01405         int                             num = 0;
01406         uint32                  len = 0;
01407         char                    buf[32];
01408 
01409         first_state     fs;
01410 
01411         while (source->getPos() < source->getSize() && num != num_tracks)
01412         {
01413                 // Read first 4 bytes of name
01414                 source->read (buf, 4);
01415                 len = source->read4high();
01416 
01417                 // Skip the FORM entries
01418                 if (!memcmp(buf,"FORM",4))
01419                 {
01420                         source->skip (4);
01421                         source->read (buf, 4);
01422                         len = source->read4high();
01423                 }
01424 
01425                 if (memcmp(buf,"EVNT",4))
01426                 {
01427                         source->skip ((len+1)&~1);
01428                         continue;
01429                 }
01430 
01431                 list = NULL;
01432                 branches = NULL;
01433                 memset(&fs, 0, sizeof(fs));
01434 
01435                 int begin = source->getPos ();
01436 
01437                 // Convert it
01438                 int chan_mask = ConvertFiletoList (source, true, fs);
01439 
01440                 // Apply the first state
01441 //              ApplyFirstState(fs, chan_mask);
01442 
01443                 // Add tempo
01444                 static const unsigned char tempo_buf[5] = { 0x51, 0x03, 0x07, 0xA1, 0x20 };
01445                 IBufferDataSource ds(tempo_buf, 5);
01446                 current = list;
01447                 ConvertSystemMessage (0, 0xFF,&ds);
01448 
01449                 // Set the list
01450                 events[num]->events = list;
01451                 events[num]->branches = branches;
01452                 events[num]->chan_mask = chan_mask;
01453 
01454                 // Increment Counter
01455                 num++;
01456 
01457                 // go to start of next track
01458                 source->seek (begin + ((len+1)&~1));
01459         }
01460 
01461         // Return how many were converted
01462         return num;
01463 }
01464 
01465 int XMidiFile::ExtractTracksFromMid (IDataSource *source, const uint32 ppqn, const int num_tracks, const bool type1)
01466 {
01467         int                     num = 0;
01468         uint32          len = 0;
01469         char            buf[32];
01470         int                     chan_mask = 0;
01471 
01472         first_state     fs;
01473         memset(&fs, 0, sizeof(fs));
01474 
01475         list = NULL;
01476         branches = NULL;
01477 
01478         while (source->getPos() < source->getSize() && num != num_tracks)
01479         {
01480                 // Read first 4 bytes of name
01481                 source->read (buf, 4);
01482                 len = source->read4high();
01483 
01484                 if (memcmp(buf,"MTrk",4))
01485                 {
01486                         source->skip (len);
01487                         continue;
01488                 }
01489 
01490                 int begin = source->getPos ();
01491 
01492                 // Convert it
01493                 chan_mask |= ConvertFiletoList (source, false, fs);
01494 
01495                 if (!type1) {
01496                         ApplyFirstState(fs, chan_mask);
01497                         AdjustTimings(ppqn);
01498                         events[num]->events = list;
01499                         events[num]->branches = branches;
01500                         branches = NULL;
01501                         list = NULL;
01502                         memset(&fs, 0, sizeof(fs));
01503                         chan_mask = 0;
01504                 }
01505                 
01506                 // Increment Counter
01507                 num++;          
01508                 source->seek (begin+len);
01509         }
01510 
01511         if (type1) { 
01512                 ApplyFirstState(fs, chan_mask);
01513                 AdjustTimings(ppqn);
01514                 events[0]->events = list;
01515                 events[0]->branches = branches;
01516                 return num == num_tracks ? 1 : 0;
01517         }
01518 
01519         // Return how many were converted
01520         return num;
01521 }
01522 
01523 int XMidiFile::ExtractTracks (IDataSource *source)
01524 {
01525         uint32          i = 0;
01526         int             start;
01527         uint32          len;
01528         uint32          chunk_len;
01529         int             count;
01530         char            buf[32];
01531 
01532         int                     format_hint = convert_type;
01533 
01534         if (convert_type >= XMIDIFILE_HINT_U7VOICE_MT_FILE)
01535                 convert_type = XMIDIFILE_CONVERT_NOCONVERSION;
01536 
01537         /*
01538         string s;
01539         
01540         config->value("config/audio/midi/reverb/enabled",s,"no");
01541         if (s == "yes") do_reverb = true;
01542         config->set("config/audio/midi/reverb/enabled",s,true);
01543 
01544         config->value("config/audio/midi/reverb/level",s,"---");
01545         if (s == "---") config->value("config/audio/midi/reverb",s,"64");
01546         reverb_value = atoi(s.c_str());
01547         if (reverb_value > 127) reverb_value = 127;
01548         else if (reverb_value < 0) reverb_value = 0;
01549         config->set("config/audio/midi/reverb/level",reverb_value,true);
01550         
01551         config->value("config/audio/midi/chorus/enabled",s,"no");
01552         if (s == "yes") do_chorus = true;
01553         config->set("config/audio/midi/chorus/enabled",s,true);
01554 
01555         config->value("config/audio/midi/chorus/level",s,"---");
01556         if (s == "---") config->value("config/audio/midi/chorus",s,"16");
01557         chorus_value = atoi(s.c_str());
01558         if (chorus_value > 127) chorus_value = 127;
01559         else if (chorus_value < 0) chorus_value = 0;
01560         config->set("config/audio/midi/chorus/level",chorus_value,true);
01561         
01562         config->value("config/audio/midi/volume_curve",s,"---");
01563         if (s == "---") config->value("config/audio/midi/gamma",s,"1");
01564         VolumeCurve.set_gamma (atof(s.c_str()));
01565         int igam = (int) ((VolumeCurve.get_gamma()*10000)+0.5); 
01566         snprintf (buf, 32, "%d.%04d", igam/10000, igam%10000); 
01567         config->set("config/audio/midi/volume_curve",buf,true);
01568         */
01569         do_reverb = false;
01570         do_chorus = false;
01571         reverb_value = 0;
01572         chorus_value = 0;
01573 
01574         // Read first 4 bytes of header
01575         source->read (buf, 4);
01576 
01577         // Could be XMidiFile
01578         if (!memcmp (buf, "FORM", 4))
01579         {
01580                 // Read length of 
01581                 len = source->read4high();
01582 
01583                 start = source->getPos();
01584                 
01585                 // Read 4 bytes of type
01586                 source->read (buf, 4);
01587 
01588                 // XDIRless XMidiFile, we can handle them here.
01589                 if (!memcmp (buf, "XMID", 4))
01590                 {       
01591                         perr << "Warning: XMidiFile doesn't have XDIR" << endl;
01592                         num_tracks = 1;
01593                         
01594                 } // Not an XMidiFile that we recognise
01595                 else if (memcmp (buf, "XDIR", 4))
01596                 {       
01597                         perr << "Not a recognised XMID" << endl;
01598                         return 0;
01599                         
01600                 } // Seems Valid
01601                 else 
01602                 {
01603                         num_tracks = 0;
01604                 
01605                         for (i = 4; i < len; i++)
01606                         {
01607                                 // Read 4 bytes of type
01608                                 source->read (buf, 4);
01609 
01610                                 // Read length of chunk
01611                                 chunk_len = source->read4high();
01612                         
01613                                 // Add eight bytes
01614                                 i+=8;
01615                                 
01616                                 if (memcmp (buf, "INFO", 4))
01617                                 {       
01618                                         // Must allign
01619                                         source->skip((chunk_len+1)&~1);
01620                                         i+= (chunk_len+1)&~1;
01621                                         continue;
01622                                 }
01623 
01624                                 // Must be at least 2 bytes long
01625                                 if (chunk_len < 2)
01626                                         break;
01627                                 
01628                                 num_tracks = source->read2();
01629                                 break;
01630                         }
01631                 
01632                         // Didn't get to fill the header
01633                         if (num_tracks == 0)
01634                         {
01635                                 perr << "Not a valid XMID" << endl;
01636                                 return 0;
01637                         }
01638                 
01639                         // Ok now to start part 2
01640                         // Goto the right place
01641                         source->seek (start+((len+1)&~1));
01642                 
01643                         // Read 4 bytes of type
01644                         source->read (buf, 4);
01645 
01646                         // Not an XMID
01647                         if (memcmp (buf, "CAT ", 4))
01648                         {
01649                                 perr << "Not a recognised XMID (" << buf[0] << buf[1] << buf[2] << buf[3] << ") should be (CAT )" << endl;
01650                                 return 0;       
01651                         }
01652                         
01653                         // Now read length of this track
01654                         len = source->read4high();
01655                         
01656                         // Read 4 bytes of type
01657                         source->read (buf, 4);
01658 
01659                         // Not an XMID
01660                         if (memcmp (buf, "XMID", 4))
01661                         {
01662                                 perr << "Not a recognised XMID (" << buf[0] << buf[1] << buf[2] << buf[3] << ") should be (XMID)" << endl;
01663                                 return 0;       
01664                         }
01665 
01666                 }
01667 
01668                 // Ok it's an XMID, so pass it to the ExtractCode
01669 
01670                 events = XMidiEvent__Calloc<XMidiEventList*>(num_tracks); //new XMidiEvent *[info.tracks];
01671                 
01672                 for (i = 0; i < num_tracks; i++)
01673                         events[i] = XMidiEvent__Calloc<XMidiEventList>();
01674 
01675                 count = ExtractTracksFromXmi (source);
01676 
01677                 if (count != num_tracks)
01678                 {
01679                         perr << "Error: unable to extract all (" << num_tracks << ") tracks specified from XMidiFile. Only ("<< count << ")" << endl;
01680                         
01681                         int i = 0;
01682                         
01683                         for (i = 0; i < num_tracks; i++) {
01684                                 events[i]->decerementCounter();
01685                                 events[i] = NULL;
01686                         }
01687                         
01688                         //delete [] events;
01689                         XMidiEvent::Free (events);
01690                         
01691                         return 0;               
01692                 }
01693 
01694                 return 1;
01695                 
01696         }// Definately a Midi
01697         else if (!memcmp (buf, "MThd", 4))
01698         {
01699                 // Simple read length of header
01700                 len = source->read4high();
01701 
01702                 if (len < 6)
01703                 {
01704                         perr << "Not a valid MIDI" << endl;
01705                         return 0;
01706                 }
01707 
01708                 int type = source->read2high();
01709                 
01710                 int actual_num = num_tracks = source->read2high();
01711 
01712                 // Type 1 only has 1 track, even though it says it has more
01713                 if (type == 1) num_tracks = 1;
01714 
01715                 events = XMidiEvent__Calloc<XMidiEventList*>(num_tracks); //new XMidiEvent *[info.tracks];
01716                 const uint32 ppqn = source->read2high();
01717 
01718                 for (i = 0; i < num_tracks; i++)
01719                         events[i] = XMidiEvent__Calloc<XMidiEventList>();
01720                 
01721                 count = ExtractTracksFromMid (source, ppqn, actual_num, type == 1);
01722 
01723                 if (count != num_tracks)
01724                 {
01725                         perr << "Error: unable to extract all (" << num_tracks << ") tracks specified from MIDI. Only ("<< count << ")" << endl;
01726                         
01727                         for (i = 0; i < num_tracks; i++) {
01728                                 events[i]->decerementCounter();
01729                                 events[i] = NULL;
01730                         }
01731                         
01732                         XMidiEvent::Free (events);
01733                         
01734                         return 0;
01735                                 
01736                 }
01737 
01738                 return 1;
01739                 
01740         }// A RIFF Midi, just pass the source back to this function at the start of the midi file
01741         else if (!memcmp (buf, "RIFF", 4))
01742         {
01743                 // Read len
01744                 len = source->read4();
01745 
01746                 // Read 4 bytes of type
01747                 source->read (buf, 4);
01748                 
01749                 // Not an RMID
01750                 if (memcmp (buf, "RMID", 4))
01751                 {
01752                         perr << "Invalid RMID" << endl;
01753                         return 0;
01754                 }
01755 
01756                 // Is a RMID
01757 
01758                 for (i = 4; i < len; i++)
01759                 {
01760                         // Read 4 bytes of type
01761                         source->read (buf, 4);
01762                         
01763                         chunk_len = source->read4();
01764                         
01765                         i+=8;
01766                                 
01767                         if (memcmp (buf, "data", 4))
01768                         {       
01769                                 // Must allign
01770                                 source->skip ((chunk_len+1)&~1);
01771                                 i+= (chunk_len+1)&~1;
01772                                 continue;
01773                         }
01774                         
01775                         return ExtractTracks (source);
01776 
01777                 }
01778                 
01779                 perr << "Failed to find midi data in RIFF Midi" << endl;
01780                 return 0;
01781         }
01782         else if (format_hint == XMIDIFILE_HINT_U7VOICE_MT_FILE) 
01783         {
01784                 return ExtractTracksFromU7V(source);
01785         }
01786         else if (format_hint == XMIDIFILE_HINT_XMIDI_MT_FILE) 
01787         {
01788                 return ExtractTracksFromXMIDIMT(source);
01789         }
01790         
01791         return 0;       
01792 }
01793 
01794 int XMidiFile::ExtractTracksFromU7V (IDataSource *source)
01795 {
01796         uint32                  i, j;
01797         int                             num = 0;
01798         uint32                  len = 0;
01799         int                             time = 0;
01800         int                             time_inc = 32;
01801 
01802 
01803         first_state     fs;
01804 
01805         list = NULL;
01806         branches = NULL;
01807         memset(&fs, 0, sizeof(fs));
01808 
01809         // Convert it
01810         int chan_mask = 0;
01811 
01812         source->seek(0);
01813         uint32 num_timbres = source->read1();
01814         pout << num_timbres << " custom timbres..." << std::endl;
01815 
01816         if (source->getSize() != 247*num_timbres+1) {
01817                 perr << "File size didn't match timbre count. Wont convert." << std::endl;
01818                 return 0;       
01819         }
01820 
01821         //
01822         // All Dev Reset
01823         //
01824 
01825         char one = 1;
01826         CreateMT32SystemMessage(time, all_dev_reset_base, 0, 1, &one);
01827         time += time_inc;
01828 
01829 
01830         // Now do each timbre and patch
01831         for (i = 0; i < num_timbres; i++)
01832         {
01833                 //
01834                 // Timbre
01835                 //
01836                 CreateMT32SystemMessage(time, timbre_base, timbre_mem_offset(i), timbre_mem_size, 0, source);
01837 
01838                 //
01839                 // Patch
01840                 //
01841 
01842                 // Default patch
01843                 PatchMemData patch_data = patch_template;
01844         
01845                 // Set the timbre num
01846                 patch_data.timbre_num = i;
01847 
01848                 CreateMT32SystemMessage(time, 
01849                                 patch_base, 
01850                                 patch_mem_offset(source->read1()-1),
01851                                 patch_mem_size,
01852                                 &patch_data );
01853 
01854                 //time += time_inc;
01855         }
01856 
01857         //
01858         // Rhythm Setup
01859         //
01860 
01861         i = 0;
01862         while (U7PercussionNotes[i])
01863         {
01864                 // Work out how many we can send at a time
01865                 for (j = i+1; U7PercussionNotes[j]; j++)
01866                 {
01867                         // If the next isn't actually the next, then we can't upload it
01868                         if (U7PercussionNotes[j-1]+1 != U7PercussionNotes[j]) break;
01869                 }
01870 
01871                 int count = j-i;
01872 
01873                 CreateMT32SystemMessage(time,
01874                                 rhythm_base, 
01875                                 rhythm_mem_offset_note(U7PercussionNotes[i]),
01876                                 rhythm_mem_size*count,
01877                                 &U7PercussionData[i] );
01878 
01879                 time += time_inc;
01880                 i+=count;
01881         }
01882 
01883         //
01884         // Set system volume
01885         //
01886 
01887         char seventy = 70;
01888 
01889         CreateMT32SystemMessage(time, system_base, system_mem_offset(masterVol), 1,&seventy);
01890         time += time_inc; 
01891 
01892         // Apply the first state
01893         //ApplyFirstState(fs, chan_mask);
01894 
01895         // Add tempo
01896         static const unsigned char tempo_buf[5] = { 0x51, 0x03, 0x07, 0xA1, 0x20 };
01897         IBufferDataSource ds(tempo_buf, 5);
01898         current = list;
01899         ConvertSystemMessage (0, 0xFF,&ds);
01900 
01901         num_tracks=1;
01902         events = XMidiEvent__Calloc<XMidiEventList*>(1); //new XMidiEvent *[info.tracks];
01903         events[0] = XMidiEvent__Calloc<XMidiEventList>();
01904         events[0]->events = list;
01905         events[0]->branches = branches;
01906         events[0]->chan_mask = chan_mask;
01907 
01908         // Increment Counter
01909         num++;
01910 
01911         // Return how many were converted
01912         return num;
01913 
01914 }
01915 
01916 int XMidiFile::ExtractTracksFromXMIDIMT (IDataSource *source)
01917 {
01918         int                             num = 0;
01919         uint32                  len = 0;
01920         int                             time = 0;
01921         int                             time_inc = 32;
01922 
01923 
01924         first_state     fs;
01925 
01926         list = NULL;
01927         branches = NULL;
01928         memset(&fs, 0, sizeof(fs));
01929 
01930         // Convert it
01931         int chan_mask = 0;
01932 
01933         source->seek(0);
01934 
01935         //
01936         // All Dev Reset
01937         //
01938 
01939         char one = 1;
01940         CreateMT32SystemMessage(time, all_dev_reset_base, 0, 1, &one);
01941         time += time_inc;
01942 
01943         // Channel assignment
01944         CreateMT32SystemMessage(time, system_base, system_mem_offset(chanAssign), 9, system_part_chans);
01945         time += time_inc;
01946 
01947         // Partial Rerserve
01948         CreateMT32SystemMessage(time, system_base, system_mem_offset(reserveSettings), 9, system_part_rsv);
01949         time += time_inc;
01950 
01951         // Reverb settings
01952         CreateMT32SystemMessage(time, system_base, 1, 3, system_init_reverb);
01953         time += time_inc;
01954 
01955         // Add tempo
01956         static const unsigned char tempo_buf[5] = { 0x51, 0x03, 0x07, 0xA1, 0x20 };
01957         IBufferDataSource ds(tempo_buf, 5);
01958         current = list;
01959         ConvertSystemMessage (0, 0xFF,&ds);
01960 
01961         num_tracks=1;
01962         events = XMidiEvent__Calloc<XMidiEventList*>(1); //new XMidiEvent *[info.tracks];
01963         events[0] = XMidiEvent__Calloc<XMidiEventList>();
01964         events[0]->events = list;
01965         events[0]->branches = branches;
01966         events[0]->chan_mask = chan_mask;
01967 
01968         // Increment Counter
01969         num++;
01970 
01971         // Return how many were converted
01972         return num;
01973 }
01974 
01975 void XMidiFile::InsertDisplayEvents()
01976 {
01977         // Change the display 
01978         current = list = events[0]->events;
01979         while (current->next) current = current->next;
01980 
01981 
01982         //
01983         // Display
01984         //
01985 
01986         const char *display = ::display;
01987         const char *display_beginning = ::display_beginning;
01988 #ifdef PENTAGRAM_IN_EXULT
01989         if (Game::get_game_type() == SERPENT_ISLE)
01990         {
01991                 display = display_serpent_isle;
01992                 display_beginning = display_beginning_si;
01993         }
01994         else if (Game::get_game_type() == BLACK_GATE)
01995         {
01996                 display = display_black_gate;
01997                 display_beginning = display_beginning_bg;
01998         }
01999 #endif
02000 
02001         CreateMT32SystemMessage(current->time, display_base, 0, display_mem_size, display );
02002         CreateMT32SystemMessage(-1, display_base, 0, display_mem_size, display_beginning );
02003 
02004         events[0]->events = list;
02005 
02006 }

Generated on Fri Jul 27 22:27:55 2007 for pentagram by  doxygen 1.4.7