public void LoadMidi(MidiFile midiFile) { _tempoChanges = new FastList <MidiFileSequencerTempoChange>(); // Combine all tracks into 1 track that is organized from lowest to highest absolute time if (midiFile.Tracks.Length > 1 || midiFile.Tracks[0].EndTime == 0) { midiFile.CombineTracks(); } _division = midiFile.Division; _eventIndex = 0; _currentTime = 0; // build synth events. _synthData = new FastList <SynthEvent>(); // Converts midi to milliseconds for easy sequencing double bpm = 120; var absTick = 0; var absTime = 0.0; var metronomeLength = 0; var metronomeTick = 0; var metronomeTime = 0.0; for (int x = 0; x < midiFile.Tracks[0].MidiEvents.Length; x++) { var mEvent = midiFile.Tracks[0].MidiEvents[x]; var synthData = new SynthEvent(mEvent); _synthData.Add(synthData); absTick += mEvent.DeltaTime; absTime += mEvent.DeltaTime * (60000.0 / (bpm * midiFile.Division)); synthData.Delta = absTime; if (mEvent.Command == MidiEventTypeEnum.Meta && mEvent.Data1 == (int)MetaEventTypeEnum.Tempo) { var meta = (MetaNumberEvent)mEvent; bpm = MidiHelper.MicroSecondsPerMinute / (double)meta.Value; _tempoChanges.Add(new MidiFileSequencerTempoChange(bpm, absTick, (int)(absTime))); } else if (mEvent.Command == MidiEventTypeEnum.Meta && mEvent.Data1 == (int)MetaEventTypeEnum.TimeSignature) { var meta = (MetaDataEvent)mEvent; var timeSignatureDenominator = (int)Math.Pow(2, meta.Data[1]); metronomeLength = (int)(_division * (4.0 / timeSignatureDenominator)); } else if (mEvent.Command == MidiEventTypeEnum.ProgramChange) { var channel = mEvent.Channel; if (!_firstProgramEventPerChannel.ContainsKey(channel)) { _firstProgramEventPerChannel[channel] = synthData; } } if (metronomeLength > 0) { while (metronomeTick < absTick) { var metronome = SynthEvent.NewMetronomeEvent(metronomeLength); _synthData.Add(metronome); metronome.Delta = metronomeTime; metronomeTick += metronomeLength; metronomeTime += metronomeLength * (60000.0 / (bpm * midiFile.Division)); } } } _synthData.Sort((a, b) => (int)(a.Delta - b.Delta)); _endTime = absTime; EndTick = absTick; }
public void LoadMidi(MidiFile midiFile) { _tempoChanges = new FastList <MidiFileSequencerTempoChange>(); _division = midiFile.Division; _eventIndex = 0; _currentTime = 0; // build synth events. _synthData = new FastList <SynthEvent>(); // Converts midi to milliseconds for easy sequencing double bpm = 120; var absTick = 0; var absTime = 0.0; var metronomeLength = 0; var metronomeTick = 0; var metronomeTime = 0.0; var previousTick = 0; foreach (var mEvent in midiFile.Events) { var synthData = new SynthEvent(_synthData.Count, mEvent); _synthData.Add(synthData); var deltaTick = mEvent.Tick - previousTick; absTick += deltaTick; absTime += deltaTick * (60000.0 / (bpm * midiFile.Division)); synthData.Time = absTime; previousTick = mEvent.Tick; if (mEvent.Command == MidiEventType.Meta && mEvent.Data1 == (int)MetaEventTypeEnum.Tempo) { var meta = (MetaNumberEvent)mEvent; bpm = MidiHelper.MicroSecondsPerMinute / (double)meta.Value; _tempoChanges.Add(new MidiFileSequencerTempoChange(bpm, absTick, (int)(absTime))); } else if (mEvent.Command == MidiEventType.Meta && mEvent.Data1 == (int)MetaEventTypeEnum.TimeSignature) { var meta = (MetaDataEvent)mEvent; var timeSignatureDenominator = (int)Math.Pow(2, meta.Data[1]); metronomeLength = (int)(_division * (4.0 / timeSignatureDenominator)); } else if (mEvent.Command == MidiEventType.ProgramChange) { var channel = mEvent.Channel; if (!_firstProgramEventPerChannel.ContainsKey(channel)) { _firstProgramEventPerChannel[channel] = synthData; } } if (metronomeLength > 0) { while (metronomeTick < absTick) { var metronome = SynthEvent.NewMetronomeEvent(_synthData.Count, metronomeLength); _synthData.Add(metronome); metronome.Time = metronomeTime; metronomeTick += metronomeLength; metronomeTime += metronomeLength * (60000.0 / (bpm * midiFile.Division)); } } } _synthData.Sort((a, b) => { if (a.Time > b.Time) { return(1); } else if (a.Time < b.Time) { return(-1); } return(a.EventIndex - b.EventIndex); }); _endTime = absTime; EndTick = absTick; }