public void Process(MetaMessage message) { #region Require if (message == null) { throw new ArgumentNullException("message"); } #endregion #region Guard if (message.MetaType != MetaType.Tempo) { return; } #endregion TempoChangeBuilder builder = new TempoChangeBuilder(message); // Set the new tempo. Tempo = builder.Tempo; }
private void Write(int deltaTicks, MetaMessage message) { if (message.MetaType == MetaType.Tempo) { // Delta time. events.AddRange(BitConverter.GetBytes(deltaTicks + offsetTicks)); // Stream ID. events.AddRange(streamID); TempoChangeBuilder builder = new TempoChangeBuilder(message); byte[] t = BitConverter.GetBytes(builder.Tempo); t[t.Length - 1] = MEVT_SHORTMSG | MEVT_TEMPO; // Event code. events.AddRange(t); offsetTicks = 0; } else { offsetTicks += deltaTicks; } }
public void Process(MetaMessage message) { #region Require if (message == null) { throw new ArgumentNullException("message"); } #endregion #region Guard if (message.MetaType != MetaType.Tempo) { if (message.MetaType == MetaType.TimeSignature) { var ts = new TimeSignatureBuilder(message); this.ClocksPerMetronomeClick = ts.ClocksPerMetronomeClick; } return; } #endregion TempoChangeBuilder builder = new TempoChangeBuilder(message); // Set the new tempo. Tempo = builder.Tempo; }
private void GetTempoDurations() { tempoDurations.Clear(); clock.Ppqn = sequence.Division; clock.Tempo = 500000; rawDuration = 0; bool tempoTrackFound = false; TempoDuration tempoDuration = new TempoDuration(); foreach (Track t in Sequence) { IEnumerator <MidiEvent> midiEnumerator = t.Iterator().GetEnumerator(); while (midiEnumerator.MoveNext()) { MidiEvent e = midiEnumerator.Current; if (e.MidiMessage.MessageType == MessageType.Meta) { var meta = (MetaMessage)e.MidiMessage; if (meta.MetaType == MetaType.Tempo) { tempoTrackFound = true; TempoChangeBuilder builder = new TempoChangeBuilder(meta); int newTempo = builder.Tempo; if (tempoDuration.Tempo != 0) { tempoDuration.Length = e.AbsoluteTicks - tempoDuration.Start; rawDuration += (long)tempoDuration.Tempo * (long)tempoDuration.Length; tempoDurations.Add(tempoDuration); tempoDuration = new TempoDuration(); } tempoDuration.Tempo = newTempo; tempoDuration.Start = e.AbsoluteTicks; } } } if (tempoTrackFound) { break; } } if (tempoDuration.Tempo == 0) { tempoDuration.Tempo = clock.Tempo; } tempoDuration.Length = sequence.GetLength() - tempoDuration.Start; rawDuration += (long)tempoDuration.Tempo * (long)tempoDuration.Length; tempoDurations.Add(tempoDuration); // Assign the duration for quick use. double oldSpeed = Speed; Speed = 1.0; duration = TicksToMilliseconds(sequence.GetLength()); Speed = oldSpeed; }
// ZUZU /// <summary> /// Change tempo /// </summary> /// <param name="tempo"></param> public void changeTempo(int tempo) { //resumeOriginalclock(); TempoChangeBuilder tc = new TempoChangeBuilder(); tc.Tempo = tempo; tc.Build(); clock.Process(tc.Result); }
private static IMidiMessage Convert(Event e, Track track) { if (e is NoteEvent) { NoteEvent note = (NoteEvent)e; if (note.Type == NoteEvent.EventType.NoteOff) { ChannelMessageBuilder b = new ChannelMessageBuilder(); b.MidiChannel = note.Channel; b.Command = ChannelCommand.NoteOff; b.Data1 = ChannelNoteToMidiPitch(note.Pitch); b.Data2 = ChannelVelocityToMidiVolume(note.Velocity); b.Build(); return b.Result; } else { ChannelMessageBuilder b = new ChannelMessageBuilder(); b.MidiChannel = note.Channel; b.Command = ChannelCommand.NoteOn; b.Data1 = ChannelNoteToMidiPitch(note.Pitch); b.Data2 = ChannelVelocityToMidiVolume(note.Velocity); b.Build(); return b.Result; } } else if (e is TempoEvent) { TempoEvent tempoEvent = (TempoEvent)e; TempoChangeBuilder builder = new TempoChangeBuilder(); // convert BPM to microseconds builder.Tempo = 60000000 / tempoEvent.TempoBpm; builder.Build(); return builder.Result; } else if (e is TimeSignatureEvent) { TimeSignatureEvent timeSignatureEvent = (TimeSignatureEvent)e; TimeSignatureBuilder builder = new TimeSignatureBuilder(); builder.Numerator = (byte)timeSignatureEvent.BeatsPerBar; builder.Denominator = (byte)timeSignatureEvent.BeatValue; builder.ClocksPerMetronomeClick = 24; builder.ThirtySecondNotesPerQuarterNote = 8; builder.Build(); return builder.Result; } else { Debug.Fail("unknown event type " + e.GetType().Name); return null; } }
public GuitarTempo(GuitarMessageList owner, MidiEvent ev) : base(owner, ev, null, GuitarMessageType.GuitarTempo) { if (ev == null) { this.Tempo = Utility.DummyTempo; } else { var cb = new TempoChangeBuilder((MetaMessage)ev.Clone()); this.Tempo = cb.Tempo; } }
public void changeTempoByPercent(int percent) { TempoChangeBuilder tc = new TempoChangeBuilder(); tc.Tempo = (getTempo() * percent) / 100; tc.Build(); bool wasPlaying; lock (lockObject) { wasPlaying = playing; Stop(); clock.Process(tc.Result); } lock (lockObject) { if (wasPlaying) { Continue(); } } }
public static NotationTrack parseMidiTrack(Midi.Track track, int division, ref Regex fingerPattern) { int microsecondsPerBeat = Midi.PpqnClock.DefaultTempo; float time = 0; TrackStatus trackStatus = new TrackStatus(); FingerChordMap fingerMap = new FingerChordMap(); List <Note> notes = new List <Note>(); Regex fingerMetaPattern = new Regex("fingering-marker-pattern:(.*)"); string name = ""; foreach (Midi.MidiEvent e in track.Iterator()) { time += e.DeltaTicks * microsecondsPerBeat / (division * 1000); switch (e.MidiMessage.MessageType) { case Midi.MessageType.Meta: Midi.MetaMessage mm = e.MidiMessage as Midi.MetaMessage; switch (mm.MetaType) { case Midi.MetaType.Tempo: Midi.TempoChangeBuilder builder = new Midi.TempoChangeBuilder(mm); microsecondsPerBeat = builder.Tempo; break; case Midi.MetaType.Text: { string text = Encoding.Default.GetString(mm.GetBytes()); var match = fingerMetaPattern.Match(text); if (match.Success) { fingerPattern = new Regex(match.Groups[1].ToString()); Debug.LogFormat("Finger Pattern found: {0}", fingerPattern.ToString()); } } break; case Midi.MetaType.Marker: if (fingerPattern != null) { string text = Encoding.Default.GetString(mm.GetBytes()); var match = fingerPattern.Match(text); if (match.Success) { //Debug.LogFormat("Finger: {0}", text); try { int pitch = int.Parse(match.Groups[1].ToString()); Finger finger = (Finger)int.Parse(match.Groups[2].ToString()); if (!fingerMap.ContainsKey(e.AbsoluteTicks)) { fingerMap[e.AbsoluteTicks] = new FingerChord(); } fingerMap[e.AbsoluteTicks][pitch] = finger; } catch (System.Exception except) { Debug.LogWarningFormat("fingering marker parse failed: {0}, {1}", text, except.Message); } } //else // Debug.LogWarningFormat("fail marker: {0}", text); } break; case Midi.MetaType.TrackName: name = Encoding.Default.GetString(mm.GetBytes()); break; } break; case Midi.MessageType.Channel: Midi.ChannelMessage cm = e.MidiMessage as Midi.ChannelMessage; if (!trackStatus.ContainsKey(cm.MidiChannel)) { trackStatus[cm.MidiChannel] = new ChannelStatus(); } var commandType = cm.Command; if (commandType == Midi.ChannelCommand.NoteOn && cm.Data2 == 0) { commandType = Midi.ChannelCommand.NoteOff; } switch (commandType) { case Midi.ChannelCommand.NoteOn: { int pitch = cm.Data1; int velocity = cm.Data2; if (pitch >= Piano.PitchMin && pitch <= Piano.PitchMax) { trackStatus[cm.MidiChannel][pitch] = new PitchStatus { tick = e.AbsoluteTicks, startTime = time, velocity = velocity } } ; } break; case Midi.ChannelCommand.NoteOff: { int pitch = cm.Data1; if (!trackStatus[cm.MidiChannel].ContainsKey(pitch)) { Debug.LogWarningFormat("Unexpected noteOff: {0}, {1}", e.AbsoluteTicks, pitch); } else { PitchStatus status = trackStatus[cm.MidiChannel][pitch]; Note note = new Note { tick = status.tick, start = status.startTime, duration = time - status.startTime, pitch = pitch, velocity = status.velocity }; if (fingerMap.ContainsKey(note.tick) && fingerMap[note.tick].ContainsKey(note.pitch)) { note.finger = fingerMap[note.tick][note.pitch]; } notes.Add(note); } } break; } break; } } NotationTrack notation = new NotationTrack(); notation.notes = notes.ToArray(); notation.name = name; return(notation); }
private void Write(int deltaTicks, MetaMessage message) { if(message.MetaType == MetaType.Tempo) { // Delta time. events.AddRange(BitConverter.GetBytes(deltaTicks + offsetTicks)); // Stream ID. events.AddRange(streamID); TempoChangeBuilder builder = new TempoChangeBuilder(message); byte[] t = BitConverter.GetBytes(builder.Tempo); t[t.Length - 1] = MEVT_SHORTMSG | MEVT_TEMPO; // Event code. events.AddRange(t); offsetTicks = 0; } else { offsetTicks += deltaTicks; } }
/// <summary> /// Creates a notechart from the specified midi path and the actual charttype /// (i.e. ExpertSingle from notes.mid). Due to the overhead necessary to /// parse a midi file. I am going to cram all midi->chart operations into /// one function call. /// This function uses the Sanford midi parser. While it is horribly slow /// on larger (e.g. RB) midis, it works without a hitch on every midi I've /// come across. /// </summary> /// <param name="chartSelection"> /// The information on which particular notechart to use. /// </param> /// <param name="chartInfo">The metadata on the chart.</param> /// <param name="BPMChanges">The list of BPM changes for this chart.</param> /// <returns> /// A filled out Notechart containing the needed information from the *.mid file. /// </returns> public static Notes ParseMidiInformationSanford(ChartSelection chartSelection, Info chartInfo, List<BPMChange> BPMChanges) { Notes notechartToReturn = new Notes(); notechartToReturn.instrument = chartSelection.instrument; notechartToReturn.difficulty = chartSelection.difficulty; // The following two switch's are used to get the proper midi terminology for // the selected track and difficulty. string instrumentPart = null; int greenKey = 0; int redKey = 0; int yellowKey = 0; int blueKey = 0; int orangeKey = 0; switch (chartSelection.instrument) { case "Single": instrumentPart = "PART GUITAR"; break; case "DoubleGuitar": instrumentPart = "PART GUITAR COOP"; break; case "DoubleBass": instrumentPart = "PART BASS"; break; case "Drums": instrumentPart = "PART DRUMS"; break; default: instrumentPart = "PART GUITAR"; break; } switch (chartSelection.difficulty) { case "Expert": greenKey = 96; redKey = 97; yellowKey = 98; blueKey = 99; orangeKey = 100; break; case "Hard": greenKey = 84; redKey = 85; yellowKey = 86; blueKey = 87; orangeKey = 88; break; case "Medium": greenKey = 72; redKey = 73; yellowKey = 74; blueKey = 75; orangeKey = 76; break; case "Easy": greenKey = 60; redKey = 61; yellowKey = 62; blueKey = 63; orangeKey = 64; break; default: greenKey = 96; redKey = 97; yellowKey = 98; blueKey = 99; orangeKey = 100; break; } Sequence mySequence = new Sequence(chartSelection.directory + "\\notes.mid"); Track trackToUse = new Track(); chartInfo.resolution = mySequence.Division; // Go through each event in the first track (which contains the BPM changes) // and parse the resulting string. Track sanTrack = mySequence[0]; foreach (Sanford.Multimedia.Midi.MidiEvent currEvent in sanTrack.Iterator()) { if (currEvent.MidiMessage.MessageType == MessageType.Meta) { MetaMessage currMessage = currEvent.MidiMessage as MetaMessage; //currTickValue += Convert.ToUInt32(splitEventString[1]); if (currMessage.MetaType == MetaType.Tempo) { TempoChangeBuilder tempoBuilder = new TempoChangeBuilder(currMessage); int midiBPMChange = tempoBuilder.Tempo; // In midi files, bpm chages are stored as "microseconds per quarter note" // and must be converted to BPM, and then into the non decimal format the game // uses. double currBPMDouble = 60000000 / (double)midiBPMChange; uint BPMToAdd = (uint)(currBPMDouble * 1000); BPMChanges.Add(new BPMChange((uint)currEvent.AbsoluteTicks, (uint)BPMToAdd)); } } } // Find the specified instrument's track for (int i = 1; i < mySequence.Count; i++) { sanTrack = mySequence[i]; Sanford.Multimedia.Midi.MidiEvent currEvent = sanTrack.GetMidiEvent(0); if (currEvent.MidiMessage.MessageType == MessageType.Meta) { MetaMessage currMessage = currEvent.MidiMessage as MetaMessage; if (currMessage.MetaType == MetaType.TrackName) { MetaTextBuilder trackName = new MetaTextBuilder(currMessage); // -If we come across a "T1 GEMS" track, we're in GH1 territory. // -GH2/FoF has both PART BASS and PART RHYTHM (one or the other depending // on the chart). if ((trackName.Text == instrumentPart) || (trackName.Text == "T1 GEMS") || ((trackName.Text == "PART RHYTHM") && (instrumentPart == "PART BASS"))) { trackToUse = sanTrack; } } } } Note currNote = new Note(); bool blankNote = true; // Scan through and record every note specific to the selected difficulty foreach (Sanford.Multimedia.Midi.MidiEvent currEvent in trackToUse.Iterator()) { // We need to specify wether a note is blank or not so we don't add // blank notes from other difficulties into the chart, but if we have // a filled out note, any nonzero tick value means we are moving to a // new note, so we must cut our ties and add this note to the chart. if ((currEvent.DeltaTicks != 0) && !blankNote) { notechartToReturn.notes.Add(currNote); currNote = new Note(); blankNote = true; } if (currEvent.MidiMessage.MessageType == MessageType.Channel) { ChannelMessage currMessage = currEvent.MidiMessage as ChannelMessage; if (currMessage.Command == ChannelCommand.NoteOn) { // Only consider notes within the octave our difficulty is in. if (((currMessage.Data1 == greenKey) || (currMessage.Data1 == redKey) || (currMessage.Data1 == yellowKey) || (currMessage.Data1 == blueKey) || (currMessage.Data1 == orangeKey)) && (currMessage.Data2 != 0)) { // If it's a new note, we need to setup the tick value of it. if (blankNote) { //currNote.TickValue = totalTickValue; currNote.tickValue = (uint)currEvent.AbsoluteTicks; blankNote = false; } if (currMessage.Data1 == greenKey) { currNote.addNote(0); } else if (currMessage.Data1 == redKey) { currNote.addNote(1); } else if (currMessage.Data1 == yellowKey) { currNote.addNote(2); } else if (currMessage.Data1 == blueKey) { currNote.addNote(3); } else if (currMessage.Data1 == orangeKey) { currNote.addNote(4); } } } } } return notechartToReturn; }
public MetaMessage BuildMessage() { var b = new TempoChangeBuilder(); b.Tempo = (int)Tempo; b.Build(); return b.Result; }
public void Process(MetaMessage message) { #region Require if(message == null) { throw new ArgumentNullException("message"); } #endregion #region Guard if(message.MetaType != MetaType.Tempo) { return; } #endregion TempoChangeBuilder builder = new TempoChangeBuilder(message); // Set the new tempo. Tempo = builder.Tempo; }
static void Main(string[] args) { bool outputMidiVelocity = false; //var filename = "01-v-drac.s3m"; //S3MFile f = S3MFile.Parse(filename); //var tempo = 60000000 / (f.Header.InitialTempo); //byte numerator = 4; //byte denominator = 4; //var speed = 3; //var skip = 0; var filename = "02-v-bewm.s3m"; S3MFile f = S3MFile.Parse(filename); var tempo = 60000000 / (f.Header.InitialTempo); byte numerator = 4; byte denominator = 4; var speed = 3; var skip = 0; outputMidiVelocity = true; /* var filename = "V-OPTION.S3M"; S3MFile f = S3MFile.Parse(filename); var tempo = 60000000 / (f.Header.InitialTempo); byte numerator = 6; byte denominator = 8; var speed = 3; var skip = 4; */ /* var filename = "V-FALCON.S3M"; S3MFile f = S3MFile.Parse(filename); var tempo = 60000000 / (1 * f.Header.InitialTempo); byte numerator = 4; byte denominator = 4; var speed = 3; var skip = 0; */ /* var filename = "V-CONTRA.IT"; S3MFile f = S3MFile.Parse(filename); var tempo = 60000000 / (1 * f.Header.InitialTempo); byte numerator = 4; byte denominator = 4; var speed = 3; var skip = 0; * */ /* var filename = "V-BLAST.S3M"; S3MFile f = S3MFile.Parse(filename); var tempo = 60000000 / (1 * f.Header.InitialTempo); byte numerator = 4; byte denominator = 4; var speed = 3; var skip = 0;*/ Sequence s = new Sequence(); Track t1 = new Track(); Track t2 = new Track(); Track t3 = new Track(); Track drums = new Track(); Track kick = new Track(); Track timeTrack = new Track(); s.Add(timeTrack); s.Add(t1); s.Add(t2); s.Add(t3); //s.Add(drums); //s.Add(kick); var drumPC = new ChannelMessageBuilder(); drumPC.MidiChannel = 09; drumPC.Command = ChannelCommand.ProgramChange; drumPC.Data1 = 0;// 79 + ce.Instrument; drumPC.Build(); drums.Insert(0, drumPC.Result); kick.Insert(0, drumPC.Result); TimeSignatureBuilder tsb = new TimeSignatureBuilder(); tsb.Numerator = numerator; tsb.Denominator = denominator; tsb.ClocksPerMetronomeClick = 24; tsb.ThirtySecondNotesPerQuarterNote = 8; tsb.Build(); timeTrack.Insert(0, tsb.Result); TempoChangeBuilder tcb = new TempoChangeBuilder(); tcb.Tempo = tempo; tcb.Build(); timeTrack.Insert(0, tcb.Result); var outputPatterns = new int[] { 5, 6, 7}; //var c1 = (from p in f.OrderedPatterns // where patterns.Contains(p.PatternNumber) // select p) // .SelectMany(p => p.Channels) // .Where(c => c.ChannelNumber == 1) // .SelectMany(ce => ce.ChannelEvents); //var c2 = (from p in f.OrderedPatterns // where patterns.Contains(p.PatternNumber) // select p) // .SelectMany(p => p.Channels) // .Where(c => c.ChannelNumber == 2) // .SelectMany(ce => ce.ChannelEvents); //var c3 = (from p in f.OrderedPatterns // where patterns.Contains(p.PatternNumber) // select p) // .SelectMany(p => p.Channels) // .Where(c => c.ChannelNumber == 3) // .SelectMany(ce => ce.ChannelEvents); var patterns = from p in f.OrderedPatterns.Skip(skip) /*where outputPatterns.Contains(p.PatternNumber) */select p; //.SelectMany(p => p.Rows); Dictionary<int, TrackInfo> tracks = new Dictionary<int, TrackInfo>(); tracks.Add(1, new TrackInfo(t1)); tracks[1].Channel = 0; tracks.Add(2, new TrackInfo(t2)); tracks[2].Channel = 1; tracks.Add(3, new TrackInfo(t3)); tracks[3].Channel = 2; var di = new TrackInfo(drums); di.Channel = 9; var mapper = new Func<ChannelEvent, int>(ce => { switch (ce.Instrument) { case 6: return 42; case 8: return 35; case 9: return 38; case 10: return 47; default: Debug.Fail(ce.Instrument.ToString()); return 0; } }); di.NoteMapper = mapper; var kickInfo = new TrackInfo(kick); kickInfo.Channel = 9; kickInfo.NoteMapper = mapper; tracks.Add(4, di); tracks.Add(5, kickInfo); var tick = 0; foreach (var pattern in patterns) { bool breakPattern = false; foreach (var row in pattern.Rows) { //if ((row.RowNumber-1) % 16 == 0) //{ // drums.Insert(tick, kickOn); // drums.Insert(tick + speed, kickOff); //} foreach (var ce in row.ChannelEvents) { if (ce == null) { //Console.Out.WriteLine("skip"); continue; } if (ce.Command == 3) { var modulo = row.RowNumber % 32; if (modulo != 0) { // sad to say, not sure why mod 8 but divide by 16 works var m8 = row.RowNumber % 8; if (m8 == 0) { var restore = tsb.Result; tsb.Numerator = (byte)(row.RowNumber / 16); tsb.Build(); var change = tsb.Result; timeTrack.Insert(tick, change); timeTrack.Insert(tick + 3, restore); } } //Debugger.Break(); // pattern break // figure out the time signature of the pattern up to this point // then go back and insert a time signature change message at the beginning // of the pattern // and another one at the end to revert //var restore = tsb.Result; //tsb.Numerator = 2; //tsb.Build(); //var change = tsb.Result; //timeTrack.Insert(rowStartTick, change); //timeTrack.Insert(tick + 3, restore); breakPattern = true; } if (!tracks.ContainsKey(ce.ChannelNumber)) continue; TrackInfo ti = tracks[ce.ChannelNumber]; if (ce.Note == -1 ) { // skip } else if( ce.Note == 0xFF) { // re-use current note, but change instrument //Console.Out.WriteLine("skip"); } else if (ce.Note == 0xFE) //off { if (ti.LastPitch != -1) { NoteOff(tick, ti); } } else { //if (ce.Volume != -1 && ce.Volume < 32) continue; if (ti.LastPitch != -1) { NoteOff(tick, ti); } //p = ProgramChange(ti.Track, tick, p, ce); var delay = 0; if (ce.Command == 19) { if (208 <= ce.Data && ce.Data <= 214) // HACK: 214 is a guess at the top range of SD commands { delay = ce.Data - 208; Debug.Assert(delay >= 0); } } NoteOn(tick + delay, ti, ce); } } tick += speed; if (breakPattern) { break; } } } foreach (var pair in tracks) { if (pair.Value.LastPitch != -1) { NoteOff(tick, pair.Value); } } foreach (MidiEvent m in drums.Iterator().Take(5)) { if (m.MidiMessage is ChannelMessage) { ChannelMessage cm = (ChannelMessage)m.MidiMessage; Console.Out.WriteLine("{0} {1}", m.AbsoluteTicks, cm.Command); } } s.Save(Path.ChangeExtension(filename, ".mid")); /* var tick = 0; var speed = 3; var lastNote = -1; var p = -1; foreach (var ce in c1) { if (ce == null || ce.Note == -1 || ce.Note == 0xFF) { tick += speed; Console.Out.WriteLine("skip"); continue; } else if (ce.Note == 0xFE) //off { lastNote = NoteOff(t, tick, lastNote); } else { if (lastNote != -1) { lastNote = NoteOff(t, tick, lastNote); } p = ProgramChange(t, tick, p, ce); var delay = 0; if (ce.Command == 19) { if (208 <= ce.Data && ce.Data <= 214) // HACK: 214 is a guess at the top range of SD commands { delay = ce.Data - 208; Debug.Assert(delay >= 0); } } lastNote = NoteOn(t, tick + delay, ce.Note); } tick += speed; } lastNote = NoteOff(t, tick, lastNote); * * */ }