public void LoadMidi(string fileName) { midiFileName = fileName; MainForm pform = (MainForm)this.MdiParent; st = pform.sthread; AudioSynthesis.Sequencer.MidiFileSequencer mseq = st.mseq; mseq.UnMuteAllChannels(); MidiMessage[] mdata = mseq.mdata; nudOffset.Value = 0; noteViewer1.Reset(); noteViewer1.mseq = mseq; noteViewer1.Invalidate(); //double time = 0; //if (mdata != null) //{ // foreach (MidiMessage mm in mdata) // { // time += (double)mm.delta; // //The current event starts at mm.delta microseconds after the previous event. // //textBox1.AppendText(mm.ToString() + " " + mm.AbsTime_ms + "usec\r\n"); // } //} }
private void btnSetChannelPriorities_Click(object sender, EventArgs e) { if (settingPriorities) { settingPriorities = false; btnSetChannelPriorities.Text = "Set Channel # Priorities"; AudioSynthesis.Sequencer.MidiFileSequencer mseq = st.mseq; mseq.MuteAllChannels(); foreach (byte channel in noteViewer1.ChannelPriorities.Keys) { mseq.ToggleChannelMuted(channel); } } else { settingPriorities = true; btnSetChannelPriorities.Text = "Click again when done."; noteViewer1.ChannelPriorities = new Dictionary <byte, int>(); } UpdateStartEndTimeAndPriorityButtons(); }
private void SaveMuzak(string filename) { AudioSynthesis.Sequencer.MidiFileSequencer mseq = st.mseq; MidiMessage[] mdata = mseq.mdata; double time = 0; int maxPixel = this.Width; Dictionary <int, MidiMessage> last = new Dictionary <int, MidiMessage>(); Dictionary <int, double> lastTime = new Dictionary <int, double>(); Dictionary <byte, int> priorities = noteViewer1.ChannelPriorities; //<midiFreq, int[] axisPlayingPriority = new int[nAxes]; Array.Clear(axisPlayingPriority, 0, nAxes); Dictionary <int, Tuple <int, List <Tuple <int, int> > > > muzak = new Dictionary <int, Tuple <int, List <Tuple <int, int> > > >(); //muzak = Dictionary<timestamp, Tuple<Duration, List<Tuple<priority, midiFreq>>>> //i.e. the song is divided into pieces of time, where each slice has a number of notes that should play. //We'll try to play them in priority order, depending on chords and what was playing previously... SortedDictionary <int, List <MuzakNote> > currentNotes = new SortedDictionary <int, List <MuzakNote> >(); int lastTimeStamp = 0; foreach (MidiMessage mm in mdata) { if (mm.channel == 255) { continue; } time = (double)mm.delta; if (!noteViewer1.ChannelPriorities.ContainsKey(mm.channel)) { continue; } bool startOk = time >= noteViewer1.startTime || noteViewer1.startTime < 0; bool endOk = time <= noteViewer1.endTime || noteViewer1.endTime < 0; if (startOk && endOk) { if (lastTime.Count == 0) { foreach (var c in channels) { lastTime.Add(c, time); } } if (!last.ContainsKey(mm.channel)) { last.Add(mm.channel, new MidiMessage(mm.channel, 0, 0, 0)); } long us = (long)(time - lastTime[mm.channel]); if (mm.command == (int)MidiEventTypeEnum.NoteOn || mm.command == (int)MidiEventTypeEnum.NoteOff) { int currentTimeStamp = mm.delta; int timeDelta = currentTimeStamp - lastTimeStamp; if (timeDelta > 0) { List <Tuple <int, int> > timeSlice = new List <Tuple <int, int> >(); muzak.Add(lastTimeStamp, new Tuple <int, List <Tuple <int, int> > >(timeDelta, timeSlice)); //muzak = Dictionary<timestamp, List<Tuple<priority, midiFreq>>> //i.e. the song is divided into pieces of time, where each slice has a number of notes that should play. //We'll try to play them in priority order, depending on chords and what was playing previously... foreach (var x in currentNotes) { int pri = x.Key; foreach (var note in x.Value) { timeSlice.Add(new Tuple <int, int>(pri, note.midiFreq)); } } lastTimeStamp = mm.delta; } //List<List<MuzakNote>> toOutput = new List<List<MuzakNote>>(); //foreach (int pri in currentNotes.Keys) //{ // toOutput.Add(currentNotes[pri]); // Console.Write(String.Join(", ", currentNotes[pri]) + " | "); //} //Console.WriteLine(""); } if (mm.command == (int)MidiEventTypeEnum.NoteOn) { int pri = priorities[mm.channel]; var toStart = new MuzakNote(mm.data1, pri, mm.channel); if (currentNotes.ContainsKey(pri)) { currentNotes[pri].Add(toStart); } else { currentNotes.Add(pri, new List <MuzakNote>() { toStart }); } } else if (mm.command == (int)MidiEventTypeEnum.NoteOff) { MuzakNote toEnd = null; bool multipleNotes = false; foreach (var notes in currentNotes.Values) { foreach (var note in notes) { if (note.channel == mm.channel && note.midiFreq == mm.data1) { toEnd = note; multipleNotes = notes.Count > 1; } } } if (toEnd != null) { if (multipleNotes) { currentNotes[toEnd.priority].Remove(toEnd); //Remove note from list at this priority } else { currentNotes.Remove(toEnd.priority); //Remove this entire priority } } } last[mm.channel] = mm; lastTime[mm.channel] = time; } } WriteMuzak(filename, muzak); }
private void btnSaveMuzak_Click(object sender, EventArgs e) { octaveOffset = 0; if (st == null || st.mseq == null) { MessageBox.Show("Not loaded - aborting"); return; } AudioSynthesis.Sequencer.MidiFileSequencer mseq = st.mseq; MidiMessage[] mdata = mseq.mdata; bool useW = cbAxisW.Checked; bool useY = cbAxisY.Checked; bool useX = cbAxisX.Checked; nAxes = 0; if (useW) { nAxes++; } if (useY) { nAxes++; } if (useX) { nAxes++; } if (nAxes == 0) { MessageBox.Show("Select at least one axis"); return; } if (noteViewer1.ChannelPriorities.Count == 0) { MessageBox.Show("No channel priorities set - aborting."); return; } int minPrioritiesSet = Math.Min(nAxes, channels.Count); if (noteViewer1.ChannelPriorities.Count < minPrioritiesSet) { if (DialogResult.OK != MessageBox.Show("Not using all axes - fewer channels than axes - okay to continue?", "Confirm", MessageBoxButtons.OKCancel)) { return; } } if (mseq != null && mseq.mdata != null) { byte minFreq = byte.MaxValue; byte maxFreq = byte.MinValue; double time; foreach (MidiMessage mm in mdata) { time = (double)mm.delta; if (!noteViewer1.ChannelPriorities.ContainsKey(mm.channel)) { continue; } bool startOk = time >= noteViewer1.startTime || noteViewer1.startTime < 0; bool endOk = time <= noteViewer1.endTime || noteViewer1.endTime < 0; if (startOk && endOk) { if (mm.command == (int)MidiEventTypeEnum.NoteOn) { channels.Add(mm.channel); minFreq = Math.Min(minFreq, mm.data1); maxFreq = Math.Max(maxFreq, mm.data1); } } } channels.Remove(255); if (maxFreq < minFreq) { MessageBox.Show("No notes played between start and end times on the selected channels. Aborting."); return; } //Avoid frequencies too high for laser int octave; string note; GetNote(maxFreq, out note, out octave); if (octave >= 6) { string max = GetNoteStr(maxFreq); DialogResult dr = MessageBox.Show("Highest frequency is " + max + "\r\nTo cut off higher notes, hit Ignore.\r\nTo shift down octaves, hit Retry.", "Pitch too high", MessageBoxButtons.AbortRetryIgnore); if (dr == DialogResult.Abort) { return; } else if (dr == DialogResult.Retry) { octaveOffset = LASER_MAX_OCTAVE - octave - 1; } else if (dr == DialogResult.Ignore) { octaveOffset = 0; } } } SaveFileDialog sfd = new SaveFileDialog(); sfd.FileName = midiFileName + ".muzak"; sfd.Filter = "*.muzak|*.muzak"; sfd.InitialDirectory = Properties.Settings.Default.midi_path; if (DialogResult.OK == sfd.ShowDialog()) { SaveMuzak(sfd.FileName); } //SaveMuzak(mf, path); }