shithub: duke3d

ref: 09a21797abe4a341f26b9d9db21b736fcf8965fc
dir: /Game/src/midi/xmidi.cpp/

View raw version
/*
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * aint32_t with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#ifndef ALPHA_LINUX_CXX
#  include <cassert>
#  include <cstdio>
#  include <cmath>
#  include <iostream>
#  include <cmath>
#endif
#include "xmidi.h"

using std::cerr;
using std::endl;
using std::string;

// Here's a bit of joy: WIN32 isn't SMP safe if we use operator new and delete.
// On the other hand, nothing else is thread-safe if we use malloc()/free().
// So, we wrap the implementations and use malloc()/calloc()/free() for WIN32, and
// the C++ thread-safe allocator for other platforms.

template<class T>
inline T* Malloc(size_t num=1)
{
#ifdef WIN32
	return static_cast<T*>(malloc(num));
#else
	return static_cast<T*>(::operator new(num));
#endif
}

template<class T>
inline T* Calloc(size_t num=1,size_t sz=0)
{
	if(!sz)
		sz=sizeof(T);
#ifdef WIN32
	return static_cast<T*>(calloc(num,sz));
#else
	size_t	total=sz*num;
	T *tmp=Malloc<T>(total);
	std::memset(tmp,0,total);
	return tmp;
#endif
}

inline void	Free(void *ptr)
{
#ifdef WIN32
	free(ptr);
#else
	::operator delete(ptr);
#endif
}

// This is used to correct incorrect patch, vol and pan changes in midi files
// The bias is just a value to used to work out if a vol and pan beint32_t with a 
// patch change. This is to ensure that the default state of a midi file is with
// the tracks centred, unless the first patch change says otherwise.
#define PATCH_VOL_PAN_BIAS	5


// This is a default set of patches to convert from MT32 to GM
// The index is the MT32 Patch nubmer and the value is the GM Patch
// This is only suitable for music that doesn'tdo timbre changes
// XMIDIs that contain Timbre changes will not convert properly
const uint8_t  XMIDI::mt32asgm[128] = {
	0,	// 0	Piano 1
	1,	// 1	Piano 2
	2,	// 2	Piano 3 (synth)
	4,	// 3	EPiano 1
	4,	// 4	EPiano 2
	5,	// 5	EPiano 3
	5,	// 6	EPiano 4
	3,	// 7	Honkytonk
	16,	// 8	Organ 1
	17,	// 9	Organ 2
	18,	// 10	Organ 3
	16,	// 11	Organ 4
	19,	// 12	Pipe Organ 1
	19,	// 13	Pipe Organ 2
	19,	// 14	Pipe Organ 3
	21,	// 15	Accordion
	6,	// 16	Harpsichord 1
	6,	// 17	Harpsichord 2
	6,	// 18	Harpsichord 3
	7,	// 19	Clavinet 1
	7,	// 20	Clavinet 2
	7,	// 21	Clavinet 3
	8,	// 22	Celesta 1
	8,	// 23	Celesta 2
	62,	// 24	Synthbrass 1 (62)
	63,	// 25	Synthbrass 2 (63)
	62,	// 26	Synthbrass 3 Bank 8
	63,	// 27	Synthbrass 4 Bank 8
	38,	// 28	Synthbass 1
	39,	// 29	Synthbass 2
	38,	// 30	Synthbass 3 Bank 8
	39,	// 31	Synthbass 4 Bank 8
	88,	// 32	Fantasy
	90,	// 33	Harmonic Pan - No equiv closest is polysynth(90) :(
	52,	// 34	Choral ?? Currently set to SynthVox(54). Should it be ChoirAhhs(52)???
	92,	// 35	Glass
	97,	// 36	Soundtrack
	99,	// 37	Atmosphere
	14,	// 38	Warmbell, sounds kind of like crystal(98) perhaps Tubular Bells(14) would be better. It is!
	54,	// 39	FunnyVox, sounds alot like Bagpipe(109) and Shania(111)
	98,	// 40	EchoBell, no real equiv, sounds like Crystal(98)
	96,	// 41	IceRain
	68,	// 42	Oboe 2001, no equiv, just patching it to normal oboe(68)
	95,	// 43	EchoPans, no equiv, setting to SweepPad
	81,	// 44	DoctorSolo Bank 8
	87,	// 45	SchoolDaze, no real equiv
	112,	// 46	Bell Singer
	80,	// 47	SquareWave
	48,	// 48	Strings 1
	48,	// 49	Strings 2 - should be 49
	44,	// 50	Strings 3 (Synth) - Experimental set to Tremollo Strings - should be 50
	45,	// 51	Pizzicato Strings
	40,	// 52	Violin 1
	40,	// 53	Violin 2 ? Viola
	42,	// 54	Cello 1
	42,	// 55	Cello 2
	43,	// 56	Contrabass
	46,	// 57	Harp 1
	46,	// 58	Harp 2
	24,	// 59	Guitar 1 (Nylon)
	25,	// 60	Guitar 2 (Steel)
	26,	// 61	Elec Guitar 1
	27,	// 62	Elec Guitar 2
	104,	// 63	Sitar
	32,	// 64	Acou Bass 1
	32,	// 65	Acou Bass 2
	33,	// 66	Elec Bass 1
	34,	// 67	Elec Bass 2
	36,	// 68	Slap Bass 1
	37,	// 69	Slap Bass 2
	35,	// 70	Fretless Bass 1
	35,	// 71	Fretless Bass 2
	73,	// 72	Flute 1
	73,	// 73	Flute 2
	72,	// 74	Piccolo 1
	72,	// 75	Piccolo 2
	74,	// 76	Recorder
	75,	// 77	Pan Pipes
	64,	// 78	Sax 1
	65,	// 79	Sax 2
	66,	// 80	Sax 3
	67,	// 81	Sax 4
	71,	// 82	Clarinet 1
	71,	// 83	Clarinet 2
	68,	// 84	Oboe
	69,	// 85	English Horn (Cor Anglais)
	70,	// 86	Bassoon
	22,	// 87	Harmonica
	56,	// 88	Trumpet 1
	56,	// 89	Trumpet 2
	57,	// 90	Trombone 1
	57,	// 91	Trombone 2
	60,	// 92	French Horn 1
	60,	// 93	French Horn 2
	58,	// 94	Tuba	
	61,	// 95	Brass Section 1
	61,	// 96	Brass Section 2
	11,	// 97	Vibes 1
	11,	// 98	Vibes 2
	99,	// 99	Syn Mallet Bank 1
	112,	// 100	WindBell no real equiv Set to TinkleBell(112)
	9,	// 101	Glockenspiel
	14,	// 102	Tubular Bells
	13,	// 103	Xylophone
	12,	// 104	Marimba
	107,	// 105	Koto
	111,	// 106	Sho?? set to Shanai(111)
	77,	// 107	Shakauhachi
	78,	// 108	Whistle 1
	78,	// 109	Whistle 2
	76,	// 110	Bottle Blow
	76,	// 111	Breathpipe no real equiv set to bottle blow(76)
	47,	// 112	Timpani
	117,	// 113	Melodic Tom
	116,	// 114	Deap Snare no equiv, set to Taiko(116)
	118,	// 115	Electric Perc 1
	118,	// 116	Electric Perc 2
	116,	// 117	Taiko
	115,	// 118	Taiko Rim, no real equiv, set to Woodblock(115)
	119,	// 119	Cymbal, no real equiv, set to reverse cymbal(119)
	115,	// 120	Castanets, no real equiv, in GM set to Woodblock(115)
	112,	// 121	Triangle, no real equiv, set to TinkleBell(112)
	55,	// 122	Orchestral Hit
	124,	// 123	Telephone
	123,	// 124	BirdTweet
	94,	// 125	Big Notes Pad no equiv, set to halo pad (94)
	98,	// 126	Water Bell set to Crystal Pad(98)
	121	// 127	Jungle Tune set to Breath Noise
};

// Same as above, except include patch changes
// so GS instruments can be used
const uint8_t  XMIDI::mt32asgs[256] = {
	0, 0,	// 0	Piano 1
	1, 0,	// 1	Piano 2
	2, 0,	// 2	Piano 3 (synth)
	4, 0,	// 3	EPiano 1
	4, 0,	// 4	EPiano 2
	5, 0,	// 5	EPiano 3
	5, 0,	// 6	EPiano 4
	3, 0,	// 7	Honkytonk
	16, 0,	// 8	Organ 1
	17, 0,	// 9	Organ 2
	18, 0,	// 10	Organ 3
	16, 0,	// 11	Organ 4
	19, 0,	// 12	Pipe Organ 1
	19, 0,	// 13	Pipe Organ 2
	19, 0,	// 14	Pipe Organ 3
	21, 0,	// 15	Accordion
	6, 0,	// 16	Harpsichord 1
	6, 0,	// 17	Harpsichord 2
	6, 0,	// 18	Harpsichord 3
	7, 0,	// 19	Clavinet 1
	7, 0,	// 20	Clavinet 2
	7, 0,	// 21	Clavinet 3
	8, 0,	// 22	Celesta 1
	8, 0,	// 23	Celesta 2
	62, 0,	// 24	Synthbrass 1 (62)
	63, 0,	// 25	Synthbrass 2 (63)
	62, 0,	// 26	Synthbrass 3 Bank 8
	63, 0,	// 27	Synthbrass 4 Bank 8
	38, 0,	// 28	Synthbass 1
	39, 0,	// 29	Synthbass 2
	38, 0,	// 30	Synthbass 3 Bank 8
	39, 0,	// 31	Synthbass 4 Bank 8
	88, 0,	// 32	Fantasy
	90, 0,	// 33	Harmonic Pan - No equiv closest is polysynth(90) :(
	52, 0,	// 34	Choral ?? Currently set to SynthVox(54). Should it be ChoirAhhs(52)???
	92, 0,	// 35	Glass
	97, 0,	// 36	Soundtrack
	99, 0,	// 37	Atmosphere
	14, 0,	// 38	Warmbell, sounds kind of like crystal(98) perhaps Tubular Bells(14) would be better. It is!
	54, 0,	// 39	FunnyVox, sounds alot like Bagpipe(109) and Shania(111)
	98, 0,	// 40	EchoBell, no real equiv, sounds like Crystal(98)
	96, 0,	// 41	IceRain
	68, 0,	// 42	Oboe 2001, no equiv, just patching it to normal oboe(68)
	95, 0,	// 43	EchoPans, no equiv, setting to SweepPad
	81, 0,	// 44	DoctorSolo Bank 8
	87, 0,	// 45	SchoolDaze, no real equiv
	112, 0,	// 46	Bell Singer
	80, 0,	// 47	SquareWave
	48, 0,	// 48	Strings 1
	48, 0,	// 49	Strings 2 - should be 49
	44, 0,	// 50	Strings 3 (Synth) - Experimental set to Tremollo Strings - should be 50
	45, 0,	// 51	Pizzicato Strings
	40, 0,	// 52	Violin 1
	40, 0,	// 53	Violin 2 ? Viola
	42, 0,	// 54	Cello 1
	42, 0,	// 55	Cello 2
	43, 0,	// 56	Contrabass
	46, 0,	// 57	Harp 1
	46, 0,	// 58	Harp 2
	24, 0,	// 59	Guitar 1 (Nylon)
	25, 0,	// 60	Guitar 2 (Steel)
	26, 0,	// 61	Elec Guitar 1
	27, 0,	// 62	Elec Guitar 2
	104, 0,	// 63	Sitar
	32, 0,	// 64	Acou Bass 1
	32, 0,	// 65	Acou Bass 2
	33, 0,	// 66	Elec Bass 1
	34, 0,	// 67	Elec Bass 2
	36, 0,	// 68	Slap Bass 1
	37, 0,	// 69	Slap Bass 2
	35, 0,	// 70	Fretless Bass 1
	35, 0,	// 71	Fretless Bass 2
	73, 0,	// 72	Flute 1
	73, 0,	// 73	Flute 2
	72, 0,	// 74	Piccolo 1
	72, 0,	// 75	Piccolo 2
	74, 0,	// 76	Recorder
	75, 0,	// 77	Pan Pipes
	64, 0,	// 78	Sax 1
	65, 0,	// 79	Sax 2
	66, 0,	// 80	Sax 3
	67, 0,	// 81	Sax 4
	71, 0,	// 82	Clarinet 1
	71, 0,	// 83	Clarinet 2
	68, 0,	// 84	Oboe
	69, 0,	// 85	English Horn (Cor Anglais)
	70, 0,	// 86	Bassoon
	22, 0,	// 87	Harmonica
	56, 0,	// 88	Trumpet 1
	56, 0,	// 89	Trumpet 2
	57, 0,	// 90	Trombone 1
	57, 0,	// 91	Trombone 2
	60, 0,	// 92	French Horn 1
	60, 0,	// 93	French Horn 2
	58, 0,	// 94	Tuba	
	61, 0,	// 95	Brass Section 1
	61, 0,	// 96	Brass Section 2
	11, 0,	// 97	Vibes 1
	11, 0,	// 98	Vibes 2
	99, 0,	// 99	Syn Mallet Bank 1
	112, 0,	// 100	WindBell no real equiv Set to TinkleBell(112)
	9, 0,	// 101	Glockenspiel
	14, 0,	// 102	Tubular Bells
	13, 0,	// 103	Xylophone
	12, 0,	// 104	Marimba
	107, 0,	// 105	Koto
	111, 0,	// 106	Sho?? set to Shanai(111)
	77, 0,	// 107	Shakauhachi
	78, 0,	// 108	Whistle 1
	78, 0,	// 109	Whistle 2
	76, 0,	// 110	Bottle Blow
	76, 0,	// 111	Breathpipe no real equiv set to bottle blow(76)
	47, 0,	// 112	Timpani
	117, 0,	// 113	Melodic Tom
	116, 0,	// 114	Deap Snare no equiv, set to Taiko(116)
	118, 0,	// 115	Electric Perc 1
	118, 0,	// 116	Electric Perc 2
	116, 0,	// 117	Taiko
	115, 0,	// 118	Taiko Rim, no real equiv, set to Woodblock(115)
	119, 0,	// 119	Cymbal, no real equiv, set to reverse cymbal(119)
	115, 0,	// 120	Castanets, no real equiv, in GM set to Woodblock(115)
	112, 0,	// 121	Triangle, no real equiv, set to TinkleBell(112)
	55, 0,	// 122	Orchestral Hit
	124, 0,	// 123	Telephone
	123, 0,	// 124	BirdTweet
	94, 0,	// 125	Big Notes Pad no equiv, set to halo pad (94)
	98, 0,	// 126	Water Bell set to Crystal Pad(98)
	121, 0	// 127	Jungle Tune set to Breath Noise
};

// Constructor
XMIDI::XMIDI(DataSource *source, int pconvert) : events(NULL),
						convert_type(pconvert), is_emidi(false),
						do_reverb(false), do_chorus(false)
{
	if (convert_type == XMIDI_CONVERT_EMIDI_GM)
	{
		is_emidi = true;
		convert_type = XMIDI_CONVERT_NOCONVERSION;
	}

	memset(bank127,0,sizeof(bank127));
	
	ExtractTracks (source);
}

XMIDI::~XMIDI()
{
	if (events)
	{
		for (int i=0; i < num_tracks; i++) {
			events[i]->DecerementCounter();
			events[i] = NULL;
		}
		//delete [] events;
		Free(events);
	}
}

XMIDIEventList *XMIDI::GetEventList (uint32_t track)
{
	if (!events)
	{
		cerr << "No midi data in loaded." << endl;
		return 0;
	}

	if (track >= num_tracks)
	{
		cerr << "Can't retrieve MIDI data, track out of range" << endl;
		return 0;
	}

	return events[track];
}

// Sets current to the new event and updates list
void XMIDI::CreateNewEvent (int time)
{
	if (!list)
	{
		list = current = Calloc<midi_event>(); //new midi_event;
		if (time > 0)
			current->time = time;
		return;
	}

	if (time < 0 || list->time > time)
	{
		midi_event *event = Calloc<midi_event>(); //new midi_event;
		event->next = list;
		list = current = event;
		return;
	}

	if (!current || current->time > time)
		current = list;

	while (current->next)
	{
		if (current->next->time > time)
		{
			midi_event *event = Calloc<midi_event>(); //new midi_event;
			
			event->next = current->next;
			current->next = event;
			current = event;
			current->time = time;
			return;
		}
		
		current = current->next;
	}

	current->next = Calloc<midi_event>(); //new midi_event;
	current = current->next;
	current->time = time;
}

//
// GetVLQ
//
// Get a Conventional Variable Length Quantity
//
int XMIDI::GetVLQ (DataSource *source, uint32_t &quant)
{
	int i;
	quant = 0;
	unsigned int data;

	for (i = 0; i < 4; i++)
	{
		data = source->read1();
		quant <<= 7;
		quant |= data & 0x7F;

		if (!(data & 0x80))
		{
			i++;
			break;
		}

	}
	return i;
}

//
// GetVLQ2
//
// Get a XMIDI Variable Length Quantity
//
int XMIDI::GetVLQ2 (DataSource *source, uint32_t &quant)
{
	int i;
	quant = 0;
	int data = 0;
	
	for (i = 0; i < 4; i++)
	{
		data = source->read1();
		if (data & 0x80)
		{
			source->skip(-1);
			break;
		}
		quant += data;
	}
	return i;
}

//
// MovePatchVolAndPan.
//
// Well, this is just a modified version of what that method used to do. This
// is a massive optimization. Speed up should be quite impressive
//
void XMIDI::ApplyFirstState(first_state &fs, int chan_mask)
{
	for (int channel = 0; channel < 16; channel++)
	{
		midi_event *patch = fs.patch[channel];
		midi_event *vol = fs.vol[channel];
		midi_event *pan = fs.pan[channel];
		midi_event *bank = fs.bank[channel];
		midi_event *reverb = NULL;
		midi_event *chorus = NULL;
		midi_event *temp;

		// Got no patch change, return and don't try fixing it
		if (!patch || !(chan_mask & 1 << channel)) continue;
#if 0
		std::cout << "Channel: " << channel+1 << std::endl;
		std::cout << "Patch: " << (unsigned int) patch->data[0] << " @ " << patch->time << std::endl;
		if (bank) std::cout << " Bank: " << (unsigned int) bank->data[1] << " @ " << bank->time << std::endl;
		if (vol) std::cout << "  Vol: " << (unsigned int) vol->data[1] << " @ " << vol->time << std::endl;
		if (pan) std::cout << "  Pan: " << ((signed int) pan->data[1])-64 << " @ " << pan->time << std::endl;
		std::cout << std::endl;
#endif

		// Copy Patch Change Event
		temp = patch;
		patch = Calloc<midi_event>(); //new midi_event;
		patch->time = temp->time;
		patch->status = channel|(MIDI_STATUS_PROG_CHANGE << 4);
		patch->data[0] = temp->data[0];

		// Copy Volume
		if (vol && (vol->time > patch->time+PATCH_VOL_PAN_BIAS || vol->time < patch->time-PATCH_VOL_PAN_BIAS))
			vol = NULL;

		temp = vol;
		vol = Calloc<midi_event>(); //new midi_event;
		vol->status = channel|(MIDI_STATUS_CONTROLLER << 4);
		vol->data[0] = 7;

		if (!temp)
		{
			vol->data[1] = 90;
		}
		else
			vol->data[1] = temp->data[1];


		// Copy Bank
		if (bank && (bank->time > patch->time+PATCH_VOL_PAN_BIAS || bank->time < patch->time-PATCH_VOL_PAN_BIAS))
			bank = NULL;

		temp = bank;
		
		bank = Calloc<midi_event>(); //new midi_event;
		bank->status = channel|(MIDI_STATUS_CONTROLLER << 4);

		if (!temp)
			bank->data[1] = 0;
		else
			bank->data[1] = temp->data[1];

		// Copy Pan
		if (pan && (pan->time > patch->time+PATCH_VOL_PAN_BIAS || pan->time < patch->time-PATCH_VOL_PAN_BIAS))
			pan = NULL;

		temp = pan;
		pan = Calloc<midi_event>(); //new midi_event;
		pan->status = channel|(MIDI_STATUS_CONTROLLER << 4);
		pan->data[0] = 10;

		if (!temp)
			pan->data[1] = 64;
		else
			pan->data[1] = temp->data[1];

		if (do_reverb)
		{
			reverb = Calloc<midi_event>(); //new midi_event;
			reverb->status = channel|(MIDI_STATUS_CONTROLLER << 4);
			reverb->data[0] = 91;
			reverb->data[1] = reverb_value;
		}

		if (do_chorus)
		{
			chorus = Calloc<midi_event>(); //new midi_event;
			chorus->status = channel|(MIDI_STATUS_CONTROLLER << 4);
			chorus->data[0] = 93;
			chorus->data[1] = chorus_value;
		}

		vol->time = 0;
		pan->time = 0;
		patch->time = 0;
		bank->time = 0;
		
		if (do_reverb && do_chorus) reverb->next = chorus;
		else if (do_reverb) reverb->next = bank;
		if (do_chorus) chorus->next = bank;
		bank->next = vol;
		vol->next = pan;
		pan->next = patch;
		
		patch->next = list;
		if (do_reverb) list = reverb;
		else if (do_chorus) list = chorus;
		else list = bank;
	}
}


//
// AdjustTimings
//
// It converts the midi's to use 120 Hz timing, and also calcs the duration of
// the notes. It also strips the tempo events, and adds it's own
//
// This is used by Midi's ONLY! It will do nothing with Xmidi
//
void XMIDI::AdjustTimings(uint32_t ppqn)
{
	uint32_t		tempo = 500000;
	uint32_t		time_prev = 0;
	uint32_t		hs_rem = 0;
	uint32_t		hs     = 0;

	ppqn *= 10000;

	// Virtual playing
	NoteStack notes;

	for (midi_event	*event = list; event; event = event->next) {

			// Note 64 bit int is required because multiplication by tempo can
			// require 52 bits in some circumstances

			uint64_t aim = event->time - time_prev;
			aim *= tempo;

			hs_rem += aim%ppqn;
			hs += aim/ppqn;
			hs += hs_rem/ppqn;
			hs_rem %= ppqn;

			time_prev = event->time;
			event->time = (hs*6)/5 + (6*hs_rem)/(5*ppqn);
				
			// Note on and note off handling
			if (event->status <= 0x9F) {

				// Add if it's a note on and remove if it's a note off
				if ((event->status>>4) == MIDI_STATUS_NOTE_ON && event->data[1]) 
					notes.Push(event);
				else {
					midi_event *prev = notes.FindAndPop(event);
					if (prev) prev->duration = event->time - prev->time;
				}

			}
			else if (event->status == 0xFF && event->data[0] == 0x51) {

				tempo = (event->buffer[0] << 16) +
					(event->buffer[1] << 8) +
					event->buffer[2];
					
				event->buffer[0] = 0x07;
				event->buffer[1] = 0xA1;
				event->buffer[2] = 0x20;
			}
	}

	//std::cout << "Max Polyphony: " << notes.GetMaxPolyphony() << std::endl;
	static const uint8_t  tempo_buf[5] = { 0x51, 0x03, 0x07, 0xA1, 0x20 };
	BufferDataSource ds((uint8_t  *)tempo_buf, 5);
	current = list;
	ConvertSystemMessage (0, 0xFF,&ds);
}


// Converts Events
//
// Source is at the first data byte
// size 1 is single data byte (ConvertEvent Only)
// size 2 is dual data byte
// size 3 is XMI Note on (ConvertNote only)
// Returns bytes converted
//
// ConvertNote is used for Note On's and Note offs
// ConvertSystemMessage is used for SysEx events and Meta events
// ConvertEvent is used for everything else

int XMIDI::ConvertEvent (const int time, uint8_t  status, DataSource *source, const int size, first_state &fs)
{
	int	data;

	data = source->read1();

	// Little hacks for EMIDI

	if (use_emidi_112 && (status >> 4) == MIDI_STATUS_PROG_CHANGE)
	{
		// Discard all normal program changes if we are using emidi 112
		return 1;
	}
	else if (is_emidi && (status >> 4) == MIDI_STATUS_CONTROLLER && data == EMIDI_CONTROLLER_PROGRAM_CHANGE)
	{
		// Convert it into a normal program change event
		use_emidi_112 = true;
		status = (status&0x0F) | (MIDI_STATUS_PROG_CHANGE<<4);
		data = source->read1();
		source->skip(-1);
	}

	if (use_emidi_113 && (status >> 4) ==  MIDI_STATUS_CONTROLLER && data == 7)
	{
		// Discard all normal volume changes if we are using emidi 113
		source->skip(1);
		return 2;
	}
	else if (is_emidi && (status >> 4) == MIDI_STATUS_CONTROLLER && data == EMIDI_CONTROLLER_VOLUME)
	{
		// Convert it into a normal program change event
		use_emidi_113 = true;
		data = 7;
	}


	// Bank changes are handled here
	if ((status >> 4) == 0xB && data == 0)
	{
		data = source->read1();
		
		bank127[status&0xF] = false;
		
		if (convert_type == XMIDI_CONVERT_MT32_TO_GM || convert_type == XMIDI_CONVERT_MT32_TO_GS
			|| convert_type == XMIDI_CONVERT_MT32_TO_GS127)
			return 2;

		CreateNewEvent (time);
		current->status = status;
		current->data[0] = 0;
		current->data[1] = data;

		// Set the bank
		if (!fs.bank[status&0xF] || fs.bank[status&0xF]->time > time) fs.bank[status&0xF] = current;

		if (convert_type == XMIDI_CONVERT_GS127_TO_GS && data == 127)
			bank127[status&0xF] = true;

		return 2;
	}

	// Handling for patch change mt32 conversion, probably should go elsewhere
	if ((status >> 4) == 0xC && (status&0xF) != 9 && convert_type != XMIDI_CONVERT_NOCONVERSION)
	{
		if (convert_type == XMIDI_CONVERT_MT32_TO_GM)
		{
			data = mt32asgm[data];
		}
		else if ((convert_type == XMIDI_CONVERT_GS127_TO_GS && bank127[status&0xF]) ||
				convert_type == XMIDI_CONVERT_MT32_TO_GS)
		{
			CreateNewEvent (time);
			current->status = 0xB0 | (status&0xF);
			current->data[0] = 0;
			current->data[1] = mt32asgs[data*2+1];

			data = mt32asgs[data*2];

			// Set the bank
			if (!fs.bank[status&0xF] || fs.bank[status&0xF]->time > time) fs.bank[status&0xF] = current;
		}
		else if (convert_type == XMIDI_CONVERT_MT32_TO_GS127)
		{
			CreateNewEvent (time);
			current->status = 0xB0 | (status&0xF);
			current->data[0] = 0;
			current->data[1] = 127;

			// Set the bank
			if (!fs.bank[status&0xF] || fs.bank[status&0xF]->time > time) fs.bank[status&0xF] = current;
		}
	}// Disable patch changes on Track 10 is doing a conversion
	else if ((status >> 4) == 0xC && (status&0xF) == 9 && convert_type != XMIDI_CONVERT_NOCONVERSION)
	{
		return size;
	}

	CreateNewEvent (time);
	current->status = status;

	current->data[0] = data;

	// Check for patch change, and update fs if req
	if ((status >> 4) == 0xC) {
		if (!fs.patch[status&0xF] || fs.patch[status&0xF]->time > time)
			fs.patch[status&0xF] = current;
	}
	// Controllers
	else if ((status >> 4) == 0xB) {
		// Volume
		if (current->data[0] == 7) {
			if (!fs.vol[status&0xF] || fs.vol[status&0xF]->time > time)
				fs.vol[status&0xF] = current;
		}
		// Pan
		else if (current->data[0] == 10) {
			if (!fs.pan[status&0xF] || fs.pan[status&0xF]->time > time)
				fs.pan[status&0xF] = current;
		}
	}

	if (size == 1)
		return 1;

	current->data[1] = source->read1();

	return 2;
}

int XMIDI::ConvertNote (const int time, const uint8_t  status, DataSource *source, const int size)
{
	uint32_t	delta = 0;
	int	data;

	data = source->read1();

	CreateNewEvent (time);
	current->status = status;

	current->data[0] = data;
	current->data[1] = source->read1();

	if (size == 2)
		return 2;

	// XMI Note On handling

	// Get the duration
	int i = GetVLQ (source, delta);
	
	// Set the duration
	current->duration = delta;

	// This is an optimization
	midi_event *prev = current;
		
	// Create a note off
	CreateNewEvent (time+delta);

	current->status = status;
	current->data[0] = data;
	current->data[1] = 0;
	
	// Optimization
	current = prev;

	return i + 2;
}

// Simple routine to convert system messages
int XMIDI::ConvertSystemMessage (const int time, const uint8_t  status, DataSource *source)
{
	int i=0;
	
	CreateNewEvent (time);
	current->status = status;
	
	// Handling of Meta events
	if (status == 0xFF)
	{
		current->data[0] = source->read1();
		i++;	
	}

	i += GetVLQ (source, current->len);

	if (!current->len)
	{
		current->buffer = NULL;
		return i;
	}
	
	current->buffer = Malloc<uint8_t >(current->len);

	source->read (reinterpret_cast<uint8_t  *>(current->buffer), current->len);

	return i+current->len;
}

// XMIDI and Midi to List. Returns bit mask of channels used
int XMIDI::ConvertFiletoList (DataSource *source, const bool is_xmi, first_state &fs)
{
	int 	time = 0;			// 120th of a second
	uint32_t 	data;
	int		end = 0;
	uint32_t	status = 0;
	int		play_size = 2;
	int		file_size = source->getSize();
	int		retval = 0;

	if (is_xmi) play_size = 3;

	use_emidi_112 = false;
	use_emidi_113 = false;

	while (!end && source->getPos() < file_size)
	{
		if (!is_xmi)
		{
			GetVLQ (source, data);
			time += data;

			data = source->read1();
		
			if (data >= 0x80)
			{
				status = data;
			}
			else
				source->skip (-1);
		}	
		else
		{
			GetVLQ2 (source, data);
			time += data;

			status = source->read1();
		}

		switch (status >> 4)
		{
			case MIDI_STATUS_NOTE_ON:
			retval |= 1 << (status & 0xF);
			ConvertNote (time, status, source, play_size);
			break;

			case MIDI_STATUS_NOTE_OFF:
			ConvertNote (time, status, source, 2);
			break;

			// 2 byte data

			case MIDI_STATUS_CONTROLLER:
			if (is_emidi)
			{
				data = source->read1();
				if (data == EMIDI_CONTROLLER_TRACK_DESIGNATION)
				{
					data = source->read1();

					// Only convert 0 and 127 tracks
					if (data == 0 || data == 127) continue;

					// Discard all others
					return 0;
				}
				else if (data == EMIDI_CONTROLLER_TRACK_EXCLUSION)
				{
					data = source->read1();

					// It's not for some other track
					if (data != 0) continue;

					// Uh oh, this track is not for 0
					return 0;
				}
				source->skip (-1);
			}
			// We can convert like normal
			
			case MIDI_STATUS_AFTERTOUCH:
			case MIDI_STATUS_PITCH_WHEEL:
			if (is_emidi && (status >> 4))
			ConvertEvent (time, status, source, 2, fs);
			break;
			

			// 1 byte data
			case MIDI_STATUS_PROG_CHANGE:
			case MIDI_STATUS_PRESSURE:
			ConvertEvent (time, status, source, 1, fs);
			break;
			

			case MIDI_STATUS_SYSEX:
			if (status == 0xFF)
			{
				int	pos = source->getPos();
				uint32_t	data = source->read1();
				
				if (data == 0x2F)					// End, of track
					end = 1;
				else if (data == 0x51 && is_xmi)	// XMIDI doesn't use tempo
				{
					GetVLQ (source, data);
					source->skip(data);
					break;
				}
				
				source->seek (pos);
			}
			ConvertSystemMessage (time, status, source);
			break;

			default:
			break;
		}

	}

	return retval;
}

// Assumes correct xmidi
int XMIDI::ExtractTracksFromXmi (DataSource *source)
{
	int				num = 0;
	uint32_t			len = 0;
	uint8_t 			buf[32];

	first_state	fs;

	while (source->getPos() < source->getSize() && num != num_tracks)
	{
		// Read first 4 bytes of name
		source->read (buf, 4);
		len = source->read4high();

		// Skip the FORM entries
		if (!memcmp(buf,"FORM",4))
		{
			source->skip (4);
			source->read (buf, 4);
			len = source->read4high();
		}

		if (memcmp(buf,"EVNT",4))
		{
			source->skip ((len+1)&~1);
			continue;
		}

		list = NULL;
		memset(&fs, 0, sizeof(fs));

		int begin = source->getPos ();

		// Convert it
		int chan_mask = ConvertFiletoList (source, true, fs);

		// Apply the first state
		ApplyFirstState(fs, chan_mask);

		// Add tempo
		static const uint8_t  tempo_buf[5] = { 0x51, 0x03, 0x07, 0xA1, 0x20 };
		BufferDataSource ds((uint8_t  *)tempo_buf, 5);
		current = list;
		ConvertSystemMessage (0, 0xFF,&ds);

		// Set the list
		events[num]->events = list;

		// Increment Counter
		num++;

		// go to start of next track
		source->seek (begin + ((len+1)&~1));
	}

	// Return how many were converted
	return num;
}

int XMIDI::ExtractTracksFromMid (DataSource *source, const uint32_t ppqn, const int num_tracks, const bool type1)
{
	int			num = 0;
	uint32_t		len = 0;
	uint8_t 		buf[32];
	int			chan_mask = 0;

	first_state	fs;
	memset(&fs, 0, sizeof(fs));

	list = NULL;

	while (source->getPos() < source->getSize() && num != num_tracks)
	{
		// Read first 4 bytes of name
		source->read (buf, 4);
		len = source->read4high();

		if (memcmp(buf,"MTrk",4))
		{
			source->skip (len);
			continue;
		}

		int begin = source->getPos ();

		// Convert it
		chan_mask |= ConvertFiletoList (source, false, fs);

		if (!type1) {
			ApplyFirstState(fs, chan_mask);
			AdjustTimings(ppqn);
			events[num]->events = list;
			list = NULL;
			memset(&fs, 0, sizeof(fs));
			chan_mask = 0;
		}
		
		// Increment Counter
		num++;		
		source->seek (begin+len);
	}

	if (type1) { 
		ApplyFirstState(fs, chan_mask);
		AdjustTimings(ppqn);
		events[0]->events = list;
		return num == num_tracks ? 1 : 0;
	}

	// Return how many were converted
	return num;
}

int XMIDI::ExtractTracks (DataSource *source)
{
	uint32_t		i = 0;
	int		start;
	uint32_t		len;
	uint32_t		chunk_len;
	int 		count;
	uint8_t 		buf[32];

	string s;
	
	do_reverb = false;
	reverb_value = 0;
	do_chorus = true;
	chorus_value = 0;


	// Read first 4 bytes of header
	source->read (buf, 4);

	// Could be XMIDI
	if (!memcmp (buf, "FORM", 4))
	{
		// Read length of 
		len = source->read4high();

		start = source->getPos();
		
		// Read 4 bytes of type
		source->read (buf, 4);

		// XDIRless XMIDI, we can handle them here.
		if (!memcmp (buf, "XMID", 4))
		{	
			cerr << "Warning: XMIDI doesn't have XDIR" << endl;
			num_tracks = 1;
			
		} // Not an XMIDI that we recognise
		else if (memcmp (buf, "XDIR", 4))
		{	
			cerr << "Not a recognised XMID" << endl;
			return 0;
			
		} // Seems Valid
		else 
		{
			num_tracks = 0;
		
			for (i = 4; i < len; i++)
			{
				// Read 4 bytes of type
				source->read (buf, 4);

				// Read length of chunk
				chunk_len = source->read4high();
			
				// Add eight bytes
				i+=8;
				
				if (memcmp (buf, "INFO", 4))
				{	
					// Must allign
					source->skip((chunk_len+1)&~1);
					i+= (chunk_len+1)&~1;
					continue;
				}

				// Must be at least 2 bytes long
				if (chunk_len < 2)
					break;
				
				num_tracks = source->read2();
				break;
			}
		
			// Didn't get to fill the header
			if (num_tracks == 0)
			{
				cerr << "Not a valid XMID" << endl;
				return 0;
			}
		
			// Ok now to start part 2
			// Goto the right place
			source->seek (start+((len+1)&~1));
		
			// Read 4 bytes of type
			source->read (buf, 4);

			// Not an XMID
			if (memcmp (buf, "CAT ", 4))
			{
				cerr << "Not a recognised XMID (" << buf[0] << buf[1] << buf[2] << buf[3] << ") should be (CAT )" << endl;
				return 0;	
			}
			
			// Now read length of this track
			len = source->read4high();
			
			// Read 4 bytes of type
			source->read (buf, 4);

			// Not an XMID
			if (memcmp (buf, "XMID", 4))
			{
				cerr << "Not a recognised XMID (" << buf[0] << buf[1] << buf[2] << buf[3] << ") should be (XMID)" << endl;
				return 0;	
			}

		}

		// Ok it's an XMID, so pass it to the ExtractCode

		events = Calloc<XMIDIEventList*>(num_tracks); //new midi_event *[info.tracks];
		
		for (i = 0; i < num_tracks; i++)
			events[i] = Calloc<XMIDIEventList>();

		count = ExtractTracksFromXmi (source);

		if (count != num_tracks)
		{
			cerr << "Error: unable to extract all (" << num_tracks << ") tracks specified from XMIDI. Only ("<< count << ")" << endl;
			
			int i = 0;
			
			for (i = 0; i < num_tracks; i++) {
				events[i]->DecerementCounter();
				events[i] = NULL;
			}
			
			//delete [] events;
			Free (events);
			
			return 0;		
		}

		return 1;
		
	}// Definately a Midi
	else if (!memcmp (buf, "MThd", 4))
	{
		// Simple read length of header
		len = source->read4high();

		if (len < 6)
		{
			cerr << "Not a valid MIDI" << endl;
			return 0;
		}

		int type = source->read2high();
		
		int actual_num = num_tracks = source->read2high();

		// Type 1 only has 1 track, even though it says it has more
		if (type == 1) num_tracks = 1;

		events = Calloc<XMIDIEventList*>(num_tracks); //new midi_event *[info.tracks];
		const uint32_t ppqn = source->read2high();

		for (i = 0; i < num_tracks; i++)
			events[i] = Calloc<XMIDIEventList>();
		
		count = ExtractTracksFromMid (source, ppqn, actual_num, type == 1);

		if (count != num_tracks)
		{
			cerr << "Error: unable to extract all (" << num_tracks << ") tracks specified from MIDI. Only ("<< count << ")" << endl;
			
			for (i = 0; i < num_tracks; i++) {
				events[i]->DecerementCounter();
				events[i] = NULL;
			}
			
			Free (events);
			
			return 0;
				
		}

		return 1;
		
	}// A RIFF Midi, just pass the source back to this function at the start of the midi file
	else if (!memcmp (buf, "RIFF", 4))
	{
		// Read len
		len = source->read4();

		// Read 4 bytes of type
		source->read (buf, 4);
		
		// Not an RMID
		if (memcmp (buf, "RMID", 4))
		{
			cerr << "Invalid RMID" << endl;
			return 0;
		}

		// Is a RMID

		for (i = 4; i < len; i++)
		{
			// Read 4 bytes of type
			source->read (buf, 4);
			
			chunk_len = source->read4();
			
			i+=8;
				
			if (memcmp (buf, "data", 4))
			{	
				// Must allign
				source->skip ((chunk_len+1)&~1);
				i+= (chunk_len+1)&~1;
				continue;
			}
			
			return ExtractTracks (source);

		}
		
		cerr << "Failed to find midi data in RIFF Midi" << endl;
		return 0;
	}
	
	return 0;	
}

//
// XMIDIEventList stuff
//
int	XMIDIEventList::Write (const uint8_t  *filename)
{
//	FILE *file = fopen (filename, "wb"); // DARKE FIXME
//	FileDataSource ds(file);
//	int ret = Write(&ds);
//	fclose (file);
//	return ret;
	return 0;
}

int XMIDIEventList::Write (DataSource *dest)
{
	int len = 0;
	
	if (!events)
	{
		cerr << "No midi data in loaded." << endl;
		return 0;
	}

	// This is so if using buffer datasource, the caller can know how big to make the buffer
	if (!dest)
	{
		// Header is 14 bytes int32_t and add the rest as well
		len = ConvertListToMTrk (NULL);
		return 14 + len;
	}
		
	dest->write1 ('M');
	dest->write1 ('T');
	dest->write1 ('h');
	dest->write1 ('d');
	
	dest->write4high (6);

	dest->write2high (0);
	dest->write2high (1);
	dest->write2high (60);	// The PPQN
		
	len = ConvertListToMTrk (dest);

	return len + 14;
}

//
// PutVLQ
//
// Write a Conventional Variable Length Quantity
//
int XMIDIEventList::PutVLQ(DataSource *dest, uint32_t value)
{
	int buffer;
	int i = 1;
	buffer = value & 0x7F;
	while (value >>= 7)
	{
		buffer <<= 8;
		buffer |= ((value & 0x7F) | 0x80);
		i++;
	}
	if (!dest) return i;
	for (int j = 0; j < i; j++)
	{
		dest->write1(buffer & 0xFF);
		buffer >>= 8;
	}
	
	return i;
}

// Converts and event list to a MTrk
// Returns bytes of the array
// buf can be NULL
uint32_t XMIDIEventList::ConvertListToMTrk (DataSource *dest)
{
	int time = 0;
	int lasttime = 0;
	midi_event	*event;
	uint32_t	delta;
	uint8_t 	last_status = 0;
	uint32_t 	i = 8;
	uint32_t 	j;
	uint32_t	size_pos=0;

	if (dest)
	{
		dest->write1('M');
		dest->write1('T');
		dest->write1('r');
		dest->write1('k');

		size_pos = dest->getPos();
		dest->skip(4);
	}

	for (event = events; event; event=event->next)
	{
		// We don't write the end of stream marker here, we'll do it later
		if (event->status == 0xFF && event->data[0] == 0x2f) {
			lasttime = event->time;
			continue;
		}

		delta = (event->time - time);
		time = event->time;

		i += PutVLQ (dest, delta);

		if ((event->status != last_status) || (event->status >= 0xF0))
		{
			if (dest) dest->write1(event->status);
			i++;
		}
		
		last_status = event->status;
		
		switch (event->status >> 4)
		{
			// 2 bytes data
			// Note off, Note on, Aftertouch, Controller and Pitch Wheel
			case 0x8: case 0x9: case 0xA: case 0xB: case 0xE:
			if (dest)
			{
				dest->write1(event->data[0]);
				dest->write1(event->data[1]);
			}
			i += 2;
			break;
			

			// 1 bytes data
			// Program Change and Channel Pressure
			case 0xC: case 0xD:
			if (dest) dest->write1(event->data[0]);
			i++;
			break;
			

			// Variable length
			// SysEx
			case 0xF:
			if (event->status == 0xFF)
			{
				if (dest) dest->write1(event->data[0]);
				i++;
			}
	
			i += PutVLQ (dest, event->len);
			
			if (event->len)
			{
				for (j = 0; j < event->len; j++)
				{
					if (dest) dest->write1(event->buffer[j]); 
					i++;
				}
			}

			break;
			

			// Never occur
			default:
			cerr << "Not supposed to see this" << endl;
			break;
		}
	}

	// Write out end of stream marker
	if (lasttime > time) i += PutVLQ (dest, lasttime-time);
	else i += PutVLQ (dest, 0);
	if (dest) {
		dest->write1(0xFF);
		dest->write1(0x2F);
	}
	i += 2+PutVLQ (dest, 0);

	if (dest)
	{
		int cur_pos = dest->getPos();
		dest->seek (size_pos);
		dest->write4high (i-8);
		dest->seek (cur_pos);
	}
	return i;
}


void XMIDIEventList::DeleteEventList (midi_event *mlist)
{
	midi_event *event;
	midi_event *next;
	
	next = mlist;
	event = mlist;

	while ((event = next))
	{
		next = event->next;
		// We only do this with sysex
		if ((event->status>>4) == 0xF && event->buffer) Free (event->buffer);
		Free (event);
	}
}

void XMIDIEventList::DecerementCounter()
{
	if (--counter < 0) {
		DeleteEventList(events);
		Free(this);
	}
}