reman3/Rayman_X/cpa/DS_Data/Projects/DumpMidi/DumpMidi.cpp

1456 lines
31 KiB
C++

// DumpMidi.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <io.h>
int PrintMidi = 0;
int PrintSampleSizes = 0;
int ExportNoteOff = 0;
enum eNotes
{
nC1 = 24, nCs1, nD1, nDs1, nE1, nF1, nFs1, nG1, nGs1, nA1, nAs1, nB1,
nC2, nCs2, nD2, nDs2, nE2, nF2, nFs2, nG2, nGs2, nA2, nAs2, nB2,
nC3, nCs3, nD3, nDs3, nE3, nF3, nFs3, nG3, nGs3, nA3, nAs3, nB3,
nC4, nCs4, nD4, nDs4, nE4, nF4, nFs4, nG4, nGs4, nA4, nAs4, nB4,
nC5, nCs5, nD5, nDs5, nE5, nF5, nFs5, nG5, nGs5, nA5, nAs5, nB5,
nC6, nCs6, nD6, nDs6, nE6, nF6, nFs6, nG6, nGs6, nA6, nAs6, nB6,
nC7, nCs7, nD7, nDs7, nE7, nF7, nFs7, nG7, nGs7, nA7, nAs7, nB7,
nC8, nCs8, nD8, nDs8, nE8, nF8, nFs8, nG8, nGs8, nA8, nAs8, nB8,
nBf1=nAs1, nBf2=nAs2, nBf3=nAs3, nBf4=nAs4, nBf5=nAs5, nBf6=nAs6, nBf7=nAs7, nBf8=nAs8,
nEf1=nDs1, nEf2=nDs2, nEf3=nDs3, nEf4=nDs4, nEf5=nDs5, nEf6=nDs6, nEf7=nDs7, nEf8=nDs8,
nLo = 0, nHi = 127
};
enum eDSCmds
{
eDS_End = 0xF0, // End of track - stop playing
eDS_Delay = 0xE0, // Delay for n loops [,n]
eDS_Tempo = 0xC0, // Change tempo [hi,lo]
eDS_On = 0x80, // Play this note [|channel,program,pitch]
eDS_Off = 0x90, // Stop this note [|channel]
eDS_Pan = 0xA0, // Set channel pan [|channel,pan]
eDS_Vol = 0xB0 // Set channel vol [|channel,vol]
};
#define NUM_MIDI_WAVS 146
//const char *cMidiPathIn = "Z:\\Rayman2\\DS\\Cpa\\Exe\\Main\\GameDn64\\World\\Sound\\";
const char *cMDXPathIn = "Z:\\Rayman2\\DS\\Cpa\\Exe\\Main\\GameDn64\\World\\Sound\\";
const char *cMidiPathIn = "C:\\Temp\\DSMusic\\Mid\\";
const char *cMidiPathOut = "C:\\Temp\\DSMusic\\Mid\\";
const char *cWavPath = "C:\\Temp\\DSMusic\\Wav\\";
const char *cBankFile = "C:\\Temp\\DSMidi0.tbl";
const char *cMidiBankFile = "C:\\Temp\\DSMidi0.sbk";
const char *cWavNames[NUM_MIDI_WAVS] =
{
"M_GPiano_C2.adpcm.swav",
"M_GPiano_Bb2.adpcm.swav",
"M_GPiano_F3.adpcm.swav",
"M_GPiano_C4.adpcm.swav",
"M_GPiano_G4.adpcm.swav",
"M_GPiano_C5.adpcm.swav",
"M_GPiano_G5.adpcm.swav",
"M_GPiano_C6.adpcm.swav",
"M_MPC2.adpcm.swav",
"M_MPG2.adpcm.swav",
"M_MPB3.adpcm.swav",
"M_ElecPiano1_C5.adpcm.swav",
"M_ElecPiano1_C6.adpcm.swav",
"M_CYC4.adpcm.swav",
"M_CYG4.adpcm.swav",
"M_HHCD5.adpcm.swav",
"M_HHDD5.adpcm.swav",
"M_Harpsichord_A3.adpcm.swav",
"M_Harpsichord_F4.adpcm.swav",
"M_Harpsichord_C5.adpcm.swav",
"M_Harpsichord_Gb5.adpcm.swav",
"M_Harpsichord_C6.adpcm.swav",
"M_Glock_C4.adpcm.swav",
"M_Glock_Bb4.adpcm.swav",
"M_Glock_F5.adpcm.swav",
"M_Glock_C6.adpcm.swav",
"M_Music_Box_C5.adpcm.swav",
"M_CGAC1.adpcm.swav",
"M_CGAD1.adpcm.swav",
"M_CGAC2.adpcm.swav",
"M_CGAA2.adpcm.swav",
"M_CGAD3.adpcm.swav",
"M_CGAF3.adpcm.swav",
"M_CGAF4.adpcm.swav",
"M_Marimba_C4.adpcm.swav",
"M_Marimba_Bb4.adpcm.swav",
"M_Marimba_F5.adpcm.swav",
"M_Marimba_C6.adpcm.swav",
"M_SHKDD4.adpcm.swav",
"M_SHKG4.adpcm.swav",
"M_SHKCD5.adpcm.swav",
"M_Dulcimer_C5.adpcm.swav",
"M_TBD3.adpcm.swav",
"M_PercOrgan_C6.adpcm.swav",
"M_SND1.adpcm.swav",
"M_BDC2.adpcm.swav",
"M_INPE2.adpcm.swav",
"M_INPF3.adpcm.swav",
"M_INPG3.adpcm.swav",
"M_INPA3.adpcm.swav",
"M_INPAD3.adpcm.swav",
"M_INPGD4.adpcm.swav",
"M_BCC1.adpcm.swav",
"M_BCD1.adpcm.swav",
"M_Accordian_G4.adpcm.swav",
"M_Accordian_A5.adpcm.swav",
"M_ABA1.adpcm.swav",
"M_ABD2.adpcm.swav",
"M_VIG2.adpcm.swav",
"M_VICD3.adpcm.swav",
"M_VIG3.adpcm.swav",
"M_VICD4.adpcm.swav",
"M_NylonStrGtr_B4.adpcm.swav",
"M_NylonStrGtr_Gb5.adpcm.swav",
"M_NylonStrGtr_Db6.adpcm.swav",
"M_StlStrGtr_G4.adpcm.swav",
"M_StlStrGtr_E5.adpcm.swav",
"M_StlStrGtr_Db6.adpcm.swav",
"M_PIG3.adpcm.swav",
"M_PICD4.adpcm.swav",
"M_PIAD4.adpcm.swav",
"M_MAC3.adpcm.swav",
"M_JazzGtr_G4.adpcm.swav",
"M_JazzGtr_E5.adpcm.swav",
"M_JazzGtr_Db6.adpcm.swav",
"M_ETC3.adpcm.swav",
"M_GtrHarmonic_C5.adpcm.swav",
"M_SNF1.adpcm.swav",
"M_BDA2.adpcm.swav",
"M_FingerBass_G3.adpcm.swav",
"M_PickBass_C3.adpcm.swav",
"M_SlapBass2_C3.adpcm.swav",
"M_SynBass3_G3.adpcm.swav",
"M_Viola_A3.adpcm.swav",
"M_Viola_F4.adpcm.swav",
"M_Viola_C5.adpcm.swav",
"M_Cello_Bb1.adpcm.swav",
"M_Cello_F2.adpcm.swav",
"M_Cello_C3.adpcm.swav",
"M_Cello_A3.adpcm.swav",
"M_Strings_Ab3.adpcm.swav",
"M_Strings_E4.adpcm.swav",
"M_Strings_Gb4.adpcm.swav",
"M_Strings_D5.adpcm.swav",
"M_Strings_C6.adpcm.swav",
"M_Pizzicato_C5.adpcm.swav",
"M_Harp_E5.adpcm.swav",
"M_Timpani_C3.adpcm.swav",
"M_ChoirOohs_G3.adpcm.swav",
"M_ChoirOohs_C4.adpcm.swav",
"M_ChoirOohs_G4.adpcm.swav",
"M_ChoirOohs_C5.adpcm.swav",
"M_ChoirOohs_G5.adpcm.swav",
"M_SynthVoice_F4.adpcm.swav",
"M_OrchHit_C4.adpcm.swav",
"M_Trombone_F3.adpcm.swav",
"M_Trombone_C4.adpcm.swav",
"M_MuteTrmpt_C5.adpcm.swav",
"M_MuteTrmpt_F5.adpcm.swav",
"M_MuteTrmpt_Bb5.adpcm.swav",
"M_FrHorn_F4.adpcm.swav",
"M_BrassSect_E4.adpcm.swav",
"M_BrassSect_C5.adpcm.swav",
"M_AltoSax_Bb4.adpcm.swav",
"M_EngHorn_C5.adpcm.swav",
"M_Bassoon_G3.adpcm.swav",
"M_Clarinet_C5.adpcm.swav",
"M_Flute_C6.adpcm.swav",
"M_Recorder_G5.adpcm.swav",
"M_PanFlute2_C5.adpcm.swav",
"M_Shakuhachi_C5.adpcm.swav",
"M_Ocarina_C5.adpcm.swav",
"M_Charang_C5.adpcm.swav",
"M_BassLead_C5.adpcm.swav",
"M_NewAgePad_C5.adpcm.swav",
"M_WarmPad_C5.adpcm.swav",
"M_PolySynth2_C5.adpcm.swav",
"M_SpaceVoice_C5.adpcm.swav",
"M_HaloPad_C5.adpcm.swav",
"M_IceRain_C5.adpcm.swav",
"M_Soundtrack_C5.adpcm.swav",
"M_Crystal_C5.adpcm.swav",
"M_Harmo.adpcm.swav",
"M_EchoDrops_C5.adpcm.swav",
"M_Flute01.adpcm.swav",
"M_Sitar2_G4.adpcm.swav",
"M_Banjo_G4.adpcm.swav",
"M_Ois01.adpcm.swav",
"M_Kalimba_C5.adpcm.swav",
"M_Bagpipes_F4.adpcm.swav",
"M_Violin_C5.adpcm.swav",
"M_Shanai_C5.adpcm.swav",
"M_Triangle.adpcm.swav",
"M_StDrum_C4.adpcm.swav",
"M_StDrum_C5.adpcm.swav",
"M_Breath_G5.adpcm.swav"
};
#define NUM_MIDI_FILES 292
const char *cMidiFiles[NUM_MIDI_FILES] =
{
"reset.mdx",
"Null1.mid",
"wat1aa.mid",
"wat1aa_1.mdx",
"wat1aa_2.mdx",
"mond.mid",
"ray.mid",
"end1.mid",
"end2.mid",
"rod1a.mid",
"ro1a_1.mdx",
"ro1a_2.mdx",
"Ro1a_3.mdx",
"rod1b.mid",
"Ro1b_3.mdx",
"ro1b_2.mdx",
"ro1b_1.mdx",
"astra.mid",
"Astra_6.mdx",
"Astra_5.mdx",
"Astra_7.mdx",
"hel3a.mid",
"hel3b.mid",
"astrb.mid",
"Astra_1.mdx",
"wha2ac.mid",
"bast1a.mid",
"bast1b.mid",
"bast3b.mid",
"nav4a.mid",
"princa.mid",
"wat1ab.mid",
"wat2.mid",
"wha2aa.mid",
"wha2a.mid",
"minea.mid",
"Ba1a_3.mdx",
"bast3a.mid",
"Ba3a_1.mdx",
"Ba3a_4.mdx",
"Ba3a_2.mdx",
"bast2a.mid",
"Ba2a_1.mdx",
"Ba1a_1.mdx",
"Cask1aa.mid",
"Cask1ab.mid",
"ca1a_1.mdx",
"ca1a_2.mdx",
"cask1b.mid",
"Ca1b_1.mdx",
"cask2a.mid",
"ca2a_1.mdx",
"ca2a_2.mdx",
"ca2a_3.mdx",
"Ca2a_4.mdx",
"Cask2b.mid",
"Ca1a_3.mdx",
"Ca2a_5.mdx",
"ly.mid",
"batan.mid",
"boata.mid",
"Boata_2.mdx",
"Boata_6.mdx",
"Boatb_1.mdx",
"boatb.mid",
"Boatb_2.mdx",
"Boatb_3.mdx",
"Boata_5.mdx",
"Ly1b_1.mdx",
"ly1b.mid",
"tietr.mid",
"CH1BA.mid",
"Ch1ba_2.mdx",
"ch1bb_1.mdx",
"Ch1bb.mid",
"ch1bb_3.mdx",
"ch1bb_2.mdx",
"ch2b.mid",
"ch2b_1.mdx",
"ch1bb_5.mdx",
"ch1bb_4.mdx",
"ch1a.mid",
"ch1a_1.mdx",
"ch1a_2.mdx",
"ch1a_3.mdx",
"Ch3a_4.mdx",
"Ch3a.mid",
"Ch3a_9.mdx",
"Ch3a_5.mdx",
"Ch3a_6.mdx",
"Ch3a_7.mdx",
"Ch3a_8.mdx",
"Ch3b.mid",
"Ch3a_1.mdx",
"Ch3a_2.mdx",
"Ch3a_3.mdx",
"earth.mid",
"ch2a.mid",
"earth2b.mid",
"Earth2_1.mdx",
"earth2a.mid",
"earth3b.mid",
"Earth3_1.mdx",
"earth3a.mid",
"Earth3_2.mdx",
"gld_1.mdx",
"globd.mid",
"gld_5.mdx",
"gld_4.mdx",
"globa.mid",
"gla_1.mdx",
"gla_2.mdx",
"gla_5.mdx",
"gla_6.mdx",
"Gla_7.mdx",
"globc.mid",
"glc_1.mdx",
"glc_2.mdx",
"glc_3.mdx",
"glb_5.mdx",
"globb.mid",
"glb_4.mdx",
"glb_3.mdx",
"morb1b.mid",
"hel12a.mid",
"hel12a_1.mdx",
"hel12a_2.mdx",
"hel12c.mid",
"hel12a_3.mdx",
"hel12b.mid",
"hel3b_5.mdx",
"wat3.mid",
"hel3b_1.mdx",
"hel3b_3.mdx",
"hel3b_4.mdx",
"hel3b_6.mdx",
"esca.mid",
"mask.mid",
"seatb.mid",
"Seatb_2.mdx",
"fo1c_6.mdx",
"for1c.mid",
"fo1c_7.mdx",
"injail.mid",
"poura.mid",
"jail20.mid",
"for2ab.mid",
"fo2ab_3.mdx",
"for2aa.mid",
"fo2ab_1.mdx",
"fo2ab_2.mdx",
"fo2ab_4.mdx",
"fo2ab_5.mdx",
"for2b.mid",
"fo2b_1.mdx",
"fo2b_2.mdx",
"fo2b_3.mdx",
"for1a.mid",
"fo1a_1.mdx",
"fo1a_2.mdx",
"fo1a_3.mdx",
"for1bb.mid",
"fo1bb_1.mdx",
"fo1bb_2.mdx",
"fo1bb_3.mdx",
"fo1bb_4.mdx",
"fo1bb_5.mdx",
"for1ba.mid",
"fo1c_1.mdx",
"fo1c_2.mdx",
"fo1c_3.mdx",
"fo1c_4.mdx",
"fo1c_5.mdx",
"nav3b.mid",
"nav3a.mid",
"Ba3a_3.mdx",
"ch1c.mid",
"ch1c_1.mdx",
"ly1b_4.mdx",
"ly1b_5.mdx",
"ly1c.mid",
"ly1b_2.mdx",
"ly1b_3.mdx",
"Ly1b_6.mdx",
"ly1a.mid",
"Ly1a_1.mdx",
"ly2b.mid",
"ly2a_2.mdx",
"ly2a.mid",
"ly2a_1.mdx",
"Ly2a_3.mdx",
"mineb.mid",
"mine.mdx",
"mine2.mdx",
"mine3.mdx",
"mine4.mdx",
"Morba.mid",
"morba_1.mdx",
"morba_3.mdx",
"morbb_4.mdx",
"Morbb.mid",
"morbb_3.mdx",
"morbb_1.mdx",
"morbb_2.mdx",
"morb1c.mid",
"poura_3.mdx",
"na3b_1.mdx",
"Na3b_5.mdx",
"na3b_2.mdx",
"Na3b_6.mdx",
"na3b_4.mdx",
"pourb.mid",
"poura_1.mdx",
"plum2a_2.mdx",
"plum2a.mid",
"plum2a_1.mdx",
"plum2a_3.mdx",
"vul1b_2.mdx",
"vul1b.mid",
"vul1b_1.mdx",
"vul1ab_1.mdx",
"Plum2a_4.mdx",
"plum3.mid",
"Plum3_3.mdx",
"Plum3_2.mdx",
"Plum5a_1.mdx",
"plum5a.mid",
"Plum5a_2.mdx",
"Plum5a_3.mdx",
"plum4a_3.mdx",
"plum4a.mid",
"Plum4a_4.mdx",
"plum4a_2.mdx",
"Plum4a_7.mdx",
"Plum4a_6.mdx",
"plum4a_1.mdx",
"polo.mid",
"Astrb_R.mdx",
"rhopa.mid",
"rhopb.mid",
"rhopc.mid",
"rhopd.mid",
"fin.mdx",
"rod2a.mid",
"rod2b.mid",
"seatad.mid",
"seatab_3.mdx",
"seatab.mid",
"seatac.mid",
"seatab_2.mdx",
"seatab_1.mdx",
"Seatb_1.mdx",
"seataa.mid",
"Seatad_3.mdx",
"Seatad_2.mdx",
"Seatad_1.mdx",
"seat23b.mid",
"Seat23_1.mdx",
"seat23a.mid",
"Seat23_2.mdx",
"inski.mid",
"sk_1.mdx",
"Skiba.mid",
"Skibb.mid",
"sk_2.mdx",
"skia.mid",
"skic.mid",
"princb.mid",
"MAINA.mid",
"MAINB.mid",
"princc.mid",
"vul2b.mid",
"vul1ab.mid",
"vul1a.mid",
"vul1aa_2.mdx",
"vul1aa.mid",
"vul1aa_3.mdx",
"vul1aa_1.mdx",
"vul2a.mid",
"vul2a_1.mdx",
"vul2a_2.mdx",
"vul2a_3.mdx",
"vul2a_4.mdx",
"wat1b.mid",
"wat1b_1.mdx",
"wat1b_2.mdx",
"wat1b_3.mdx",
"wat1b_4.mdx",
"Astra_8.mdx",
"wat_1.mdx",
"wat.mid",
"null.mid"
};
long lLargestOfAll = 0;
long lWavLengths[NUM_MIDI_WAVS];
unsigned char bUsedWav[NUM_MIDI_WAVS];
long lMaxWavLength[16];
long lMaxWavTotal;
typedef struct _tdstMidiHeader
{
unsigned uTotalSampleLen; // Memory needed to load in all samples for this track
unsigned uTimer; // Initial tempo
unsigned char uSamplesToLoad[(NUM_MIDI_WAVS + 3) & ~3]; // Samples to load (stop when sample num == 255, never loads ALL of them)
} tdstMidiHeader;
// Translation table - search by program & note no., resulting index is sample to play
typedef struct _midi_trans
{
unsigned char uProgram;
unsigned char uLoNote;
unsigned char uHiNote;
unsigned char uKeyNote;
} MIDI_TRANS;
unsigned char prog_trans[][2] =
{
{ 13, 9 },
{ 48, 44 },
{ 49, 44 },
{ 255, 255 }
};
MIDI_TRANS trans_table[] =
{
{ 1, nLo, nF1, nDs2 },
{ 1, nFs1, nCs2, nDs3 },
{ 1, nD2, nA2, nG3 },
{ 1, nBf2, nEf3, nC4 },
{ 1, nE3, nA3, nG4 },
{ 1, nBf3, nEf4, nC5 },
{ 1, nE4, nA4, nG5 },
{ 1, nBf4, nHi, nDs6 },
{ 3, nLo, nCs2, nC3 },
{ 3, nF3, nE4, nG3 },
{ 3, nG4, nHi, nB4 },
{ 4, nLo, nFs4, nC5 },
{ 4, nG4, nHi, nC6 },
{ 5, nLo, nC5, nC5 },
{ 5, nD5, nG5, nG5 },
{ 5, nCs6, nD6, nCs6 },
{ 5, nEf6, nHi, nDs6 },
{ 6, nLo, nCs3, nA3 },
{ 6, nD3, nGs3, nDs4 },
{ 6, nA3, nEf4, nFs4 },
{ 6, nE4, nA4, nDs5 },
{ 6, nBf4, nHi, nFs5 },
{ 9, nLo, nF3, nD4 },
{ 9, nFs3, nCs4, nA4 },
{ 9, nD4, nFs4, nCs5 },
{ 9, nG4, nHi, nF5 },
{ 10, nLo, nHi, nCs5 },
{ 11, nLo, nC2, nC2 },
{ 11, nD2, nG2, nD2 },
{ 11, nA2, nF3, nC3 },
{ 11, nG3, nB3, nA3 },
{ 11, nC4, nE4, nD4 },
{ 11, nF4, nC5, nF4 },
{ 11, nD5, nHi, nF5 },
{ 12, nLo, nF3, nC4 },
{ 12, nFs3, nCs4, nAs4 },
{ 12, nD4, nGs4, nF5 },
{ 12, nA4, nHi, nC6 },
{ 14, nLo, nEf5, nDs5 },
{ 14, nE5, nG5, nG5 },
{ 14, nG6, nHi, nCs6 },
{ 15, nLo, nHi, nC5 },
{ 16, nLo, nHi, nD4 },
{ 17, nLo, nHi, nDs6 },
{ 18, nLo, nF2, nD2 },
{ 18, nG2, nHi, nC3 },
{ 19, nLo, nG3, nE3 },
{ 19, nA3, nF4, nF4 },
{ 19, nG4, nGs4, nG4 },
{ 19, nA4, nA4, nA4 },
{ 19, nBf4, nG5, nAs4 },
{ 19, nGs5, nHi, nG5 },
{ 20, nLo, nC2, nC2 },
{ 20, nD2, nHi, nD2 },
{ 21, nLo, nF4, nG4 },
{ 21, nFs4, nHi, nGs5 },
{ 22, nLo, nGs2, nA2 },
{ 22, nA2, nHi, nD3 },
{ 23, nLo, nBf3, nG3 },
{ 23, nB3, nD4, nCs4 },
{ 23, nEf4, nA4, nG4 },
{ 23, nBf4, nHi, nCs5 },
{ 24, nLo, nD3, nF4 },
{ 24, nEf3, nA3, nAs4 },
{ 24, nBf3, nHi, nDs5 },
{ 25, nLo, nB2, nG3 },
{ 25, nC3, nGs3, nE4 },
{ 25, nA3, nHi, nCs5 },
{ 26, nLo, nGs4, nG4 },
{ 26, nA4, nD5, nCs5 },
{ 26, nEf5, nHi, nAs5 },
{ 27, nLo, nHi, nC4 },
{ 28, nLo, nB2, nG3 },
{ 28, nC3, nGs3, nE4 },
{ 28, nA3, nHi, nCs5 },
{ 29, nLo, nHi, nC4 },
{ 31, nLo, nHi, nFs4 },
{ 32, nLo, nB2, nC2 },
{ 32, nC3, nHi, nC3 },
{ 33, nLo, nHi, nG2 },
{ 34, nLo, nHi, nC2 },
{ 37, nLo, nHi, nC2 },
{ 39, nLo, nHi, nG2 },
{ 41, nLo, nCs3, nB3 },
{ 41, nD3, nGs3, nG4 },
{ 41, nA3, nHi, nC5 },
{ 43, nLo, nCs1, nAs1 },
{ 43, nD1, nA1, nF2 },
{ 43, nBf1, nE2, nC3 },
{ 43, nF2, nHi, nA3 },
{ 44, nLo, nB2, nGs3 },
{ 44, nC3, nE3, nE4 },
{ 44, nF3, nB3, nFs4 },
{ 44, nC4, nG4, nD5 },
{ 44, nGs4, nHi, nC6 },
{ 45, nLo, nHi, nE5 },
{ 46, nLo, nHi, nA5 },
{ 47, nLo, nHi, nFs3 },
{ 53, nLo, nA2, nG3 },
{ 53, nBf2, nEf3, nC4 },
{ 53, nE3, nA3, nG4 },
{ 53, nBf3, nEf4, nC5 },
{ 53, nE4, nHi, nG5 },
{ 54, nLo, nHi, nCs5 },
{ 55, nLo, nHi, nDs4 },
{ 57, nLo, nG2, nF3 },
{ 57, nGs2, nHi, nC4 },
{ 59, nLo, nD4, nC5 },
{ 59, nEf4, nG4, nF5 },
{ 59, nGs4, nHi, nAs5 },
{ 60, nLo, nHi, nF4 },
{ 61, nLo, nG3, nE4 },
{ 61, nGs3, nHi, nC5 },
{ 65, nLo, nHi, nAs4 },
{ 69, nLo, nHi, nC5 },
{ 70, nLo, nHi, nG3 },
{ 71, nLo, nHi, nC5 },
{ 73, nLo, nHi, nDs6 },
{ 74, nLo, nHi, nB5 },
{ 75, nLo, nHi, nCs5 },
{ 77, nLo, nHi, nF5 },
{ 79, nLo, nHi, nFs5 },
{ 84, nLo, nHi, nC5 },
{ 87, nLo, nHi, nC5 },
{ 88, nLo, nHi, nC5 },
{ 89, nLo, nHi, nC5 },
{ 90, nLo, nHi, nC5 },
{ 91, nLo, nHi, nC5 },
{ 94, nLo, nHi, nC5 },
{ 96, nLo, nHi, nC5 },
{ 97, nLo, nHi, nC5 },
{ 98, nLo, nHi, nC5 },
{ 100, nLo, nHi, nFs4 },
{ 102, nLo, nHi, nC5 },
{ 103, nLo, nHi, nFs4 },
{ 104, nLo, nHi, nGs4 },
{ 105, nLo, nHi, nB4 },
{ 106, nLo, nHi, nFs4 },
{ 108, nLo, nHi, nC5 },
{ 109, nLo, nHi, nA4 },
{ 110, nLo, nHi, nCs5 },
{ 111, nLo, nHi, nC5 },
{ 112, nLo, nHi, nFs5 },
{ 114, nLo, nC5, nC4 },
{ 114, nG5, nHi, nC5 },
{ 121, nLo, nHi, nG5 },
{ 255, 255, 255, 255 }
};
typedef struct {
char ID[4];
unsigned int uLength;
} CHUNK_HEADER;
template <class ITEM> void Swap(ITEM *ptr)
{
if (sizeof(ITEM)==2)
{
unsigned char *p = (unsigned char *)ptr, v;
v = p[0]; p[0] = p[1]; p[1] = v;
}
if (sizeof(ITEM)==4)
{
unsigned char *p = (unsigned char *)ptr, v;
v = p[0]; p[0] = p[3]; p[3] = v;
v = p[1]; p[1] = p[2]; p[2] = v;
}
}
void GetNext(unsigned char **pBuffer, long *plFileSize, void *pOut, int iSize)
{
memcpy(pOut, *pBuffer, iSize);
(*pBuffer) += iSize;
(*plFileSize) -= iSize;
}
#define GETNEXT(x) GetNext(&pB, &lLen, &x, sizeof(x))
unsigned GetVarLen(unsigned char *&pB, long &lLen, unsigned char uStartWith = 0)
{
unsigned uValue = uStartWith;
for (;;)
{
unsigned char uDeltaByte;
GETNEXT(uDeltaByte);
uValue = (uValue << 7) | (uDeltaByte & 0x7F);
if ((uDeltaByte & 0x80) == 0)
break;
}
return uValue;
}
void Decode(unsigned char *pBuffer, long lFileSize, const char *pOutputName)
{
unsigned char *pB = pBuffer;
long lLen = lFileSize;
CHUNK_HEADER h;
GETNEXT(h);
if ((h.ID[0] != 'M') || (h.ID[1] != 'T') || (h.ID[2] != 'h') || (h.ID[3] != 'd'))
{
printf("No midi header\n");
return;
}
Swap(&h.uLength);
unsigned short uFormat;
GETNEXT(uFormat);
Swap(&uFormat);
if (uFormat != 0)
{
printf("Not type 0\n");
return;
}
unsigned short uNumTracks;
GETNEXT(uNumTracks);
Swap(&uNumTracks);
if (uNumTracks != 1)
{
printf("Not just 1 track\n");
return;
}
unsigned uPlayerTempo = 4167; // Default to approx 120 bpm
unsigned uInitialTempo = uPlayerTempo;
unsigned uDivision;
int iHaveCmd = 0;
unsigned char uTimeLo, uTimeHi;
GETNEXT(uTimeHi);
GETNEXT(uTimeLo);
if (uTimeHi & 0x80)
{
unsigned char uFramesPerSec = (uTimeHi ^ 0xFF) + 1;
unsigned char uSubFrameTime = uTimeLo;
printf("Code the frames / subframes bit!\n");
}
else
{
unsigned short uPPQN = (unsigned short)uTimeHi * 256 + uTimeLo;
uDivision = uPPQN;
uPlayerTempo = 500000 / uDivision;
}
// Done with the header
for (;;)
{
GETNEXT(h);
Swap(&h.uLength);
if ((h.ID[0] == 'M') && (h.ID[1] == 'T') && (h.ID[2] == 'r') && (h.ID[3] == 'k'))
break;
pB += h.uLength;
}
// Now got the track
unsigned uTime = 0;
unsigned uDataLen = lLen - h.uLength;
unsigned char uStatus = 0;
bool bEndTrack = false;
// Which programs are selected for the 16 channels (so can work out pitch change for note-on)
unsigned char uPrograms[16];
memset(uPrograms, 0, sizeof(uPrograms));
unsigned char uProgramAdded[NUM_MIDI_WAVS];
memset(uProgramAdded, 0, sizeof(uProgramAdded));
unsigned char uProgramLoad[NUM_MIDI_WAVS];
memset(uProgramLoad, 255, sizeof(uProgramLoad));
unsigned uProgramIndex = 0;
// Tracks which channels are on/off
unsigned char uChannelOnOff[16][128];
memset(uChannelOnOff, 0, sizeof(uChannelOnOff));
unsigned char *pDSData = new unsigned char[256000];
unsigned char *pDS = pDSData;
unsigned uTotalWavSize = 0;
while ((lLen > uDataLen) && (!bEndTrack))
{
unsigned uDelta = GetVarLen(pB, lLen);
uTime += uDelta;
if (uDelta != 0)
{
*pDS++ = eDS_Delay;
*pDS++ = uDelta;
}
unsigned char uCmd;
unsigned char uData1;
GETNEXT(uData1);
if (uData1 & 0x80)
{
uCmd = uData1;
if (uCmd < 0xF0)
uStatus = uCmd;
else if (uCmd < 0xF8)
uStatus = 0;
GETNEXT(uData1);
}
else
uCmd = uStatus;
if (uCmd == 0xF0)
{
unsigned uEventLen = GetVarLen(pB, lLen, uData1);
pB += uEventLen;
lLen -= uEventLen;
}
else if (uCmd == 0xFF)
{
switch (uData1)
{
case 0x2F:
{
unsigned char uSkip;
GETNEXT(uSkip);
bEndTrack = true;
}
break;
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
{
// Track names, comments, other stuff
unsigned char uType = uData1;
unsigned char uLen;
GETNEXT(uLen);
pB += uLen;
lLen -= uLen;
}
break;
case 0x51:
{
// Tempo
unsigned char uLen;
GETNEXT(uLen);
if (uLen == 3)
{
unsigned char uByte;
GETNEXT(uByte);
unsigned uTempo = uByte;
uTempo <<= 8;
GETNEXT(uByte);
uTempo |= uByte;
uTempo <<= 8;
GETNEXT(uByte);
uTempo |= uByte;
uPlayerTempo = uTempo / uDivision;
if (uPlayerTempo > 65535)
printf("Tempo is too big!\n");
if (iHaveCmd == 0)
uInitialTempo = uPlayerTempo;
// HI-LO ORDER!!!
*pDS++ = eDS_Tempo;
*pDS++ = (unsigned char)((uPlayerTempo >> 8) & 0xFF);
*pDS++ = (unsigned char)(uPlayerTempo & 0xFF);
}
}
break;
case 0x54:
{
// SMPTE offset
unsigned char uLen;
GETNEXT(uLen);
pB += uLen;
lLen -= uLen;
}
break;
case 0x58:
{
// Time signature
unsigned char uLen;
GETNEXT(uLen);
pB += uLen;
lLen -= uLen;
}
break;
case 0x59:
{
// Key signature
unsigned char uLen;
GETNEXT(uLen);
pB += uLen;
lLen -= uLen;
}
break;
case 0x7F:
{
// Any proprietary event
unsigned ulLen = GetVarLen(pB, lLen);
pB += ulLen;
lLen -= ulLen;
}
break;
default:
printf("MISSED A CODE : %u\n", uData1);
bEndTrack = true;
break;
}
}
else if ((uCmd & 0x80) == 0)
{
printf("BAD MIDI FILE\n");
return;
}
else
{
iHaveCmd = 1;
unsigned char uType = uCmd >> 4;
unsigned char uData = uCmd & 0x0F;
switch (uType)
{
case 8:
// Note off
{
unsigned char uChannel = uData;
unsigned char uNote = uData1;
unsigned char uVelocity;
GETNEXT(uVelocity);
if (uPrograms[uChannel] == 127)
break;
if (uChannelOnOff[uChannel][uNote] == 0)
{
// printf("Channel %u.%u already off!\n", uChannel, uNote);
}
else
uChannelOnOff[uChannel][uNote]--;
if (ExportNoteOff)
*pDS++ = eDS_Off | uChannel;
if (PrintMidi)
printf("%04X %02X\tOFF\t%02X %02X %02X\n", uTime, uDelta, uChannel, uNote, uVelocity);
}
break;
case 9:
// Note on
{
unsigned char uChannel = uData;
unsigned char uNote = uData1;
unsigned char uVelocity;
GETNEXT(uVelocity);
if (uVelocity == 0)
{
if (uPrograms[uChannel] == 127)
break;
if (ExportNoteOff)
*pDS++ = eDS_Off | uChannel;
if (uChannelOnOff[uChannel][uNote] == 0)
{
// printf("Channel %u.%u already off!\n", uChannel, uNote);
}
else
uChannelOnOff[uChannel][uNote]--;
// Really a note off
if (PrintMidi)
printf("%04X %02X\tOFF\t%02X %02X %02X\n", uTime, uDelta, uChannel, uNote, uVelocity);
}
else
{
for (int i = 0 ; ; i++)
{
if (trans_table[i].uProgram == 255)
{
// printf("Didn't find the note-on %u\n", uPrograms[uChannel]);
break;
// bEndTrack = true;
}
if ((uPrograms[uChannel] == trans_table[i].uProgram) &&
(uNote >= trans_table[i].uLoNote) &&
(uNote <= trans_table[i].uHiNote))
{
*pDS++ = eDS_On | uChannel;
*pDS++ = (unsigned char)(i & 0xFF);
*pDS++ = (unsigned char)(uNote - trans_table[i].uKeyNote);
*pDS++ = (unsigned char)uVelocity;
if (uChannelOnOff[uChannel][uNote] == 127)
printf("Channel %u.%u already on!\n", uChannel, uNote);
else
uChannelOnOff[uChannel][uNote]++;
if (lWavLengths[i & 0xFF] > lMaxWavLength[uChannel])
lMaxWavLength[uChannel] = lWavLengths[i & 0xFF];
bUsedWav[i & 0xFF] = 1;
if (uProgramAdded[i & 0xFF] == 0)
{
uProgramAdded[i & 0xFF] = 1;
uProgramLoad[uProgramIndex++] = i & 0xFF;
uTotalWavSize += lWavLengths[i & 0xFF];
uTotalWavSize = (uTotalWavSize + 3) & ~3;
}
break;
}
}
if (PrintMidi)
printf("%04X %02X\tON\t%02X %02X %02X\n", uTime, uDelta, uChannel, uNote, uVelocity);
}
}
break;
case 10:
// Aftertouch (key pressure)
{
unsigned char uChannel = uData;
unsigned char uNote = uData1;
unsigned char uPressure;
GETNEXT(uPressure);
}
break;
case 11:
// Control change
{
unsigned char uChannel = uData;
unsigned char uController = uData1;
unsigned char uContValue;
GETNEXT(uContValue);
if (uController == 7)
{
// Change volume for uChannel to uContValue (0-127)
*pDS++ = eDS_Vol | uChannel;
*pDS++ = uContValue;
}
else if (uController == 10)
{
// Change pan for uChannel to uContValue (0-left, 64-mid, 127-right)
*pDS++ = eDS_Pan | uChannel;
*pDS++ = uContValue;
}
}
break;
case 12:
// Program (patch) change
{
unsigned char uChannel = uData;
unsigned char uProgram = uData1;
for (int i = 0 ; prog_trans[i][0] != 255 ; i++)
{
if (prog_trans[i][0] == uProgram)
{
uProgram = prog_trans[i][1];
break;
}
}
uPrograms[uChannel] = uProgram;
if (PrintMidi)
printf("%04X %02X\tPATCH\tChannel %u uses %u\n", uTime, uDelta, uChannel, uProgram);
}
break;
case 13:
// Channel pressure
{
unsigned char uChannel = uData;
unsigned char uPressure = uData1;
}
break;
case 14:
// Pitch wheel
{
unsigned char uChannel = uData;
unsigned char uD1 = uData1, uD2;
GETNEXT(uD2);
unsigned short uWheel = ((unsigned short)uD1) | (((unsigned short)uD2)<<7);
}
break;
case 15:
// Status continuation stuff
break;
}
}
}
*pDS++ = eDS_End;
if (pOutputName != NULL)
{
FILE *ff = fopen(pOutputName, "wb");
if (ff != NULL)
{
tdstMidiHeader header;
header.uTotalSampleLen = uTotalWavSize;
header.uTimer = uInitialTempo;
memset(header.uSamplesToLoad, 255, sizeof(header.uSamplesToLoad));
memcpy(header.uSamplesToLoad, uProgramLoad, sizeof(uProgramLoad));
fwrite(&header, sizeof(header), 1, ff);
fwrite(pDSData, pDS - pDSData, 1, ff);
unsigned uLen = pDS - pDSData;
while (uLen & 3)
{
fputc(0, ff);
uLen++;
}
fclose(ff);
}
}
delete[] pDSData;
}
void DecodeFile(const char *pFilename, const char *pOutputName)
{
int i;
FILE *fp = fopen(pFilename, "rb");
if (fp == NULL)
{
printf("Unable to open %s\n", pFilename);
return;
}
fseek(fp, 0, SEEK_END);
long lFileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
unsigned char *pBuffer = new unsigned char[lFileSize];
fread(pBuffer, 1, lFileSize, fp);
fclose(fp);
for (i = 0 ; i < 16 ; i++)
lMaxWavLength[i] = 0;
memset(bUsedWav, 0, sizeof(bUsedWav));
Decode(pBuffer, lFileSize, pOutputName);
delete[] pBuffer;
long lTotal = 0;
for (i = 0 ; i < 16 ; i++)
{
// if (PrintSampleSizes)
// printf("Channel %2d requires %6ld\n", i, lMaxWavLength[i]);
lTotal += lMaxWavLength[i];
}
if (PrintSampleSizes)
printf("Total for %s is %ld\n", pFilename, lTotal);
if (lTotal > lMaxWavTotal)
lMaxWavTotal = lTotal;
lTotal = 0;
for (i = 0 ; i < NUM_MIDI_WAVS ; i++)
if (bUsedWav[i])
lTotal += lWavLengths[i];
printf("Total wav space to load 'em all is %ld\n", lTotal);
if (lTotal > lLargestOfAll)
lLargestOfAll = lTotal;
}
long GetFileLength(const char *pName)
{
FILE *fp = fopen(pName, "rb");
if (fp == NULL)
return 0;
fseek(fp, 0, SEEK_END);
long lLen = ftell(fp);
fclose(fp);
return lLen;
}
long GetFileLength(FILE *fp)
{
long lCurrent = ftell(fp);
fseek(fp, 0, SEEK_END);
long lLen = ftell(fp);
fseek(fp, lCurrent, SEEK_SET);
return lLen;
}
void AppendFile(FILE *fp, const char *pName)
{
FILE *fAdd = fopen(pName, "rb");
if (fAdd == NULL)
return;
fseek(fAdd, 0, SEEK_END);
long lLen = ftell(fAdd);
fseek(fAdd, 0, SEEK_SET);
char *pTempBuffer = new char[lLen];
fread(pTempBuffer, lLen, 1, fAdd);
fclose(fAdd);
fwrite(pTempBuffer, lLen, 1, fp);
delete[] pTempBuffer;
}
void BuildWavBank()
{
FILE *fBank = fopen(cBankFile, "wb");
if (fBank == NULL)
{
printf("Unable to create %s\n", cBankFile);
return;
}
unsigned uNumWavs = NUM_MIDI_WAVS;
fwrite(&uNumWavs, sizeof(uNumWavs), 1, fBank);
unsigned uOffset = ftell(fBank) + uNumWavs * 2 * sizeof(unsigned);
unsigned u;
for (u = 0 ; u < uNumWavs ; u++)
{
char strWav[_MAX_PATH];
strcpy(strWav, cWavPath);
strcat(strWav, cWavNames[u]);
unsigned uLen = (unsigned)GetFileLength(strWav);
if (uLen == 0)
{
printf("Unable to open %s\n", strWav);
unsigned uNull = 0;
fwrite(&uNull, sizeof(uNull), 1, fBank);
fwrite(&uNull, sizeof(uNull), 1, fBank);
}
else
{
fwrite(&uOffset, sizeof(uOffset), 1, fBank);
fwrite(&uLen, sizeof(uLen), 1, fBank);
uOffset += uLen;
}
}
for (u = 0 ; u < uNumWavs ; u++)
{
char strWav[_MAX_PATH];
strcpy(strWav, cWavPath);
strcat(strWav, cWavNames[u]);
AppendFile(fBank, strWav);
}
fclose(fBank);
}
void BuildMidiBank()
{
FILE *fBank = fopen(cMidiBankFile, "wb");
if (fBank == NULL)
{
printf("Unable to create %s\n", cMidiBankFile);
return;
}
unsigned uNumFiles = NUM_MIDI_FILES;
fwrite(&uNumFiles, sizeof(uNumFiles), 1, fBank);
unsigned uOffset = ftell(fBank) + uNumFiles* 2 * sizeof(unsigned);
unsigned u;
for (u = 0 ; u < uNumFiles ; u++)
{
const char *pPtr = strrchr(cMidiFiles[u], '.');
if (pPtr == NULL)
{
printf("BAD FILE NAME : %s\n", cMidiFiles[u]);
unsigned uNull = 0;
fwrite(&uNull, sizeof(uNull), 1, fBank);
fwrite(&uNull, sizeof(uNull), 1, fBank);
}
else
{
if (stricmp(pPtr, ".mdx") == 0)
{
char strMidi[_MAX_PATH];
strcpy(strMidi, cMDXPathIn);
strcat(strMidi, cMidiFiles[u]);
unsigned uLen = (unsigned)GetFileLength(strMidi);
fwrite(&uOffset, sizeof(uOffset), 1, fBank);
fwrite(&uLen, sizeof(uLen), 1, fBank);
uOffset += uLen;
}
else if (stricmp(pPtr, ".mid") == 0)
{
char strMidi[_MAX_PATH];
strcpy(strMidi, cMidiPathOut);
strcat(strMidi, cMidiFiles[u]);
char *pPtr = strrchr(strMidi, '.');
strcpy(pPtr, ".dsm");
unsigned uLen = (unsigned)GetFileLength(strMidi);
fwrite(&uOffset, sizeof(uOffset), 1, fBank);
fwrite(&uLen, sizeof(uLen), 1, fBank);
uOffset += uLen;
}
else
{
printf("BAD FILE NAME : %s\n", cMidiFiles[u]);
unsigned uNull = 0;
fwrite(&uNull, sizeof(uNull), 1, fBank);
fwrite(&uNull, sizeof(uNull), 1, fBank);
}
}
}
for (u = 0 ; u < uNumFiles ; u++)
{
const char *pPtr = strrchr(cMidiFiles[u], '.');
if (pPtr == NULL)
{
printf("BAD FILE NAME : %s\n", cMidiFiles[u]);
}
else
{
if (stricmp(pPtr, ".mdx") == 0)
{
char strMidi[_MAX_PATH];
strcpy(strMidi, cMDXPathIn);
strcat(strMidi, cMidiFiles[u]);
AppendFile(fBank, strMidi);
}
else if (stricmp(pPtr, ".mid") == 0)
{
char strMidi[_MAX_PATH];
strcpy(strMidi, cMidiPathOut);
strcat(strMidi, cMidiFiles[u]);
char *pPtr = strrchr(strMidi, '.');
strcpy(pPtr, ".dsm");
AppendFile(fBank, strMidi);
}
else
{
printf("BAD FILE NAME : %s\n", cMidiFiles[u]);
}
}
}
fclose(fBank);
}
int _tmain(int argc, _TCHAR* argv[])
{
int i;
for (i = 0 ; i < NUM_MIDI_WAVS ; i++)
{
TCHAR wav_file[_MAX_PATH];
strcpy(wav_file, cWavPath);
strcat(wav_file, cWavNames[i]);
FILE *fm = fopen(wav_file, "rb");
if (fm != NULL)
{
fseek(fm, 0, SEEK_END);
lWavLengths[i] = ftell(fm);
fclose(fm);
}
else
lWavLengths[i] = 0;
}
lMaxWavTotal = 0;
if (argc == 2)
{
DecodeFile(argv[1], "C:\\TEMP\\DSMIDIFILE.BIN");
}
else if (argc == 1)
{
for (i = 0 ; i < NUM_MIDI_FILES ; i++)
{
char *pPtr = strrchr(cMidiFiles[i], '.');
if ((pPtr != NULL) && (stricmp(pPtr, ".mid") == 0))
{
char cFile[_MAX_PATH];
strcpy(cFile, cMidiPathIn);
strcat(cFile, cMidiFiles[i]);
char cDSFile[_MAX_PATH];
strcpy(cDSFile, cMidiPathOut);
strcat(cDSFile, cMidiFiles[i]);
pPtr = strrchr(cDSFile, '.');
strcpy(pPtr, ".dsm");
DecodeFile(cFile, cDSFile);
}
}
}
else
{
return 0;
}
printf("Max required = %ld\n", lMaxWavTotal);
printf("Total required = %ld\n", lLargestOfAll);
BuildWavBank();
BuildMidiBank();
return 0;
}