protected bool ReadTrack(int midifiletrk, bool indtsigs, clsTrks.Array <List <clsFileStream.clsOO> > oo) //trk0 = first non-conductor trk //* return false if midi trk data in trk0 (eg midi ON, OFF, patch, ...) { InitTrack(); //if (trk >= 0) FileStream.OO[trk] = new List<clsFileStream.clsOO>(); clsTrks.T trk = (midifiletrk >= 0) ? new clsTrks.T(P.F.Trks, midifiletrk) : null; FileStream.StrmLL.ResetCurrentLLN(); int delta = MReaderTrk.ReadIntV(); int ticks = 0; byte status = 0; //usually >= 0x80 int chan = -1; int seq = -1; //bool sustainon = false; //set only only if P.frmStart.chkMidiFileSustain.Checked //bool[] sustained = new bool[128]; //set only only if P.frmStart.chkMidiFileSustain.Checked while (delta >= 0) //not EOF { seq++; ticks += delta; if (TPQNConv) { ticks = (ticks * TPQNMult) / TPQNDiv; //should normally not need rounding } byte b = MReaderTrk.ReadByte(); if (b >= 0x80) //new status { status = b; chan = -1; if (status < 0xf0) { chan = status & 0x0f; b = MReaderTrk.ReadByte(); //not sysex or metaev } if (Format == 0) { midifiletrk = chan; if (chan < 0) { trk = new clsTrks.T(P.F.Trks, 0); } else { trk = new clsTrks.T(P.F.Trks, midifiletrk); } } } switch (status & 0xf0) { case 0x90: //ON case 0x80: //OFF //* 2 data bytes if (midifiletrk < 0) { return(false); } //int chan = status & 0x0f; //byte pitch = (byte)(b + FileStream.Transpose); byte pitch = b; byte vel = MReaderTrk.ReadByte(); bool on = (status & 0xf0) == 0x90 && (vel > 0); //* throw new TestException(); if (on) { FileStream.UpdateChanOnTotals(trk, chan, pitch); } FileStream.ChanAllCount[trk][chan]++; FileStream.StrmLL.InsertShortEv(seq, ticks, midifiletrk, status, b, vel); if (!Excl10 || chan != 9) { oo[new clsTrks.T(P.F.Trks, midifiletrk)].Add(new clsFileStream.clsOO( ticks, on, chan, pitch, vel, P.F.TicksPerQI)); } break; case 0xa0: //poly key pressure case 0xb0: //control change case 0xe0: //pitch wheel //* 2 data bytes //if (trk < 0) return true; if (midifiletrk < 0) //ignore { MReaderTrk.ReadByte(); break; } byte c = MReaderTrk.ReadByte(); if (FileStream.Title[trk].StartsWith("Cakewalk TTS-1")) { break; //kludge to get around Sonar bug } if ((status & 0xf0) == 0xe0) //pitchbend { if (b != 0 || c != 64) { FileStream.indPitchBend[trk] = true; //not middle value } } //else if (P.frmStart.chkMidiFileSustain.Checked && (!Excl10 || chan != 9)) { // if ((status & 0xf0) == 0xb0 && b == 64) { //sustain // sustainon = (c > 64); // if (!sustainon) { //sustainon -> sustainoff // for (int i = 0; i < 128; i++) { // if (sustained[i]) { // FileStream.OO[trk].Add(new clsFileStream.clsOO(ticks, false, chan, i, 0, P.F.TicksPerQI)); // sustained[i] = false; // } // } // } // } //} FileStream.StrmLL.InsertShortEv(seq, ticks, midifiletrk, status, b, c); FileStream.ChanAllCount[trk][status & 0x0f]++; break; case 0xc0: //program change (patch) //* 1 data byte //if (trk < 0) return false; if (midifiletrk < 0) { break; //ignore } if (FileStream.Title[trk].StartsWith("Cakewalk TTS-1")) { break; //kludge to get around Sonar bug } //if (!FileStream.Summary) FileStream.InsertShortEv(ticks, trk, status, b); FileStream.StrmLL.InsertShortEv(seq, ticks, midifiletrk, status, b); FileStream.ChanAllCount[trk][status & 0x0f]++; break; case 0xd0: //channel pressure //if (trk < 0) return false; if (midifiletrk < 0) { break; } //* 1 data byte //if (!FileStream.Summary && FileStream.TrkSelect[trk]) { //if (!FileStream.Summary) { FileStream.StrmLL.InsertShortEv(seq, ticks, midifiletrk, status, b); //} FileStream.ChanAllCount[trk][status & 0x0f]++; break; case 0xf0: //system common messages int len; switch (status) { case 0xf0: //sysex start case 0xf7: //sysex end len = MReaderTrk.ReadIntV(); byte[] sysdata = MReaderTrk.ReadBytes(len); FileStream.StrmLL.InsertSystemEv(seq, ticks, midifiletrk, status, sysdata); status = 0; //sysex cancels running status break; case 0xff: //meta event status = 0; //metaev cancels running status byte type = MReaderTrk.ReadByte(); len = MReaderTrk.ReadIntV(); byte[] metadata; switch (type) { case 0x03: //title metadata = MReaderTrk.ReadBytes(len); string title = Encoding.Default.GetString(metadata, 0, metadata.Length); if (midifiletrk == -1) { FileStream.ProjectTitle = title; } else { FileStream.Title[trk] = title; } FileStream.StrmLL.InsertTitleEv(seq, ticks, midifiletrk, metadata); break; //case 0x21: //device (port) number // if (len != 1) throw new MidiFileException(); // int pp = (int)MReaderTrk.ReadUIntF(1); // if (pp != 0) Debug.WriteLine("MidiPortNumber: " + pp + " found - ignored"); // break; //case 0x09: //device (port) name // //MReaderTrk.ReadBytes(len); //ignore metaev // break; case 0x51: //tempo ////if (!IsCondTrk(midifiletrk)) { //// MReaderTrk.ReadBytes(len); //ignore //// Debug.WriteLine("Invalid tempo found on track " + midifiletrk + " - ignored"); //// break; ////} if (len != 3) { throw new MidiFileException(); } int data = (int)MReaderTrk.ReadUIntF(3); FileStream.TempoMap.Add(ticks, data); FileStream.StrmLL.InsertTempoEv(seq, ticks, data); break; case 0x58: //tsig ////if (!IsCondTrk(midifiletrk)) { //// MReaderTrk.ReadBytes(len); //ignore //// Debug.WriteLine("Invalid time signature found on track " + midifiletrk + " - ignored"); //// break; ////} if (len != 4) { throw new MidiFileException(); } int nn = (int)MReaderTrk.ReadUIntF(1); int dd = (int)MReaderTrk.ReadUIntF(1); MReaderTrk.ReadUIntF(1); //bb - not used MReaderTrk.ReadUIntF(1); //cc - not used if (indtsigs) { int tsigdd = (int)Math.Pow(2, dd); clsMTime.clsBBT bbt = new clsMTime.clsBBT(ticks); P.frmStart.TraceLoad("add tsig " + nn + "/" + tsigdd + " ticks " + ticks + " from midifile"); //P.F.MTime.UpdateTSigsTicks(nn, tsigdd, ticks); if (ticks == 0) { P.F.MTime.AddTSigFirst(nn, tsigdd); } else { P.F.MTime.AddTSig(nn, tsigdd, ticks, adj: true); } } else { P.frmStart.TraceLoad("bypass tsig from midifile at ticks " + ticks); } break; case 0x59: //key sig //if (!IsCondTrk(midifiletrk)) { // MReaderTrk.ReadBytes(len); //ignore // MessageBox.Show("Invalid key signature found on track " + midifiletrk + " - ignored"); // break; //} if (len != 2) { throw new MidiFileException(); } int midikey = MReaderTrk.ReadIntSByte(); midikey = Math.Min(Math.Max(midikey, -7), 7); string scale = MajMin(MReaderTrk.ReadUIntF(1)); P.frmStart.TraceLoad("add midifile key to _MidiKeys at ticks " + ticks); P.F._MidiKeys.Add(midikey, scale, ticks); break; case 0x01: //text metadata = MReaderTrk.ReadBytes(len); //other metaev FileStream.StrmLL.InsertMetaEv(seq, ticks, midifiletrk, type, metadata); if (IsCondTrk(midifiletrk)) { string text = Encoding.Default.GetString(metadata, 0, metadata.Length); if (ticks == 0) //general text about the midifile? { FileStream.Text00.Add(text); } } break; case 0x2f: //end of track MaxMidiTicks = Math.Max(MaxMidiTicks, ticks); break; //don't put in stream!!! default: metadata = MReaderTrk.ReadBytes(len); //other metaev FileStream.StrmLL.InsertMetaEv(seq, ticks, midifiletrk, type, metadata); break; } break; default: status = 0; //probably throw new MidiFileException(); //not sysex or metaev } break; default: break; } delta = MReaderTrk.ReadIntV(); if (delta < 0) { break; } } MReaderTrk.Close(); //if (P.F.MTime.TSigsSrc == clsMTime.eSource.None) P.F.MTime.TSigsSrc = clsMTime.eSource.Midi; return(true); }
internal bool ReadFile(bool firsttime) { if (!OpenFile()) { return(false); } clsTrks.Array <List <clsFileStream.clsOO> > oo; if (!ReadHeader(firsttime, out oo)) { return(false); } FileStream.OnCount = new clsTrks.Array <int>(0); FileStream.OnCountX10 = new clsTrks.Array <int>(0); FileStream.ChanOnCount = new clsTrks.Array <int[]>(delegate() { return(new int[16]); }); FileStream.ChanAllCount = new clsTrks.Array <int[]>(delegate() { return(new int[16]); }); FileStream.TrkMaxPitch = new clsTrks.Array <int>(0); FileStream.TrkMinPitch = new clsTrks.Array <int>(127); FileStream.indPitchBend = new clsTrks.Array <bool>(false); FileStream.TrkType = new clsTrks.Array <clsFileStream.eTrkType>(clsFileStream.eTrkType.NoStyle); FileStream.ChordNeg = new clsTrks.Array <float>(-1f); FileStream.Poly = new clsTrks.Array <float>(-1f); //FileStream.PitchBend = new clsPitchBend[NumTrks]; //FileStream.Title = clsTrks.Array<string>.NewClass(delegate () { return ""; }); FileStream.Title = new clsTrks.Array <string>(""); if (FileStream.TrkSelect == null) { FileStream.TrkSelect = new clsTrks.Array <bool>(true); } P.F._MidiKeys = new clsKeysTicks(0, "major"); //FileStream.MidiFileKeys = new clsKeys(0, "major"); //* NumMidiTrks excludes header, includes conductor trk if (P.F.CondTrkEmpty) //not format 0 { for (int midifiletrk = 0; midifiletrk < NumMidiFileTrks; midifiletrk++) { if (!ReadTrack(midifiletrk - 1, firsttime, oo)) { P.F.CondTrkEmpty = false; FileStream.TrkSelect = null; //force reinit with new NumTrks Debug.WriteLine("Channel events found in conductor track - re-reading midi file"); return(false); } } } else { for (int midifiletrk = 0; midifiletrk < NumMidiFileTrks; midifiletrk++) { if (!ReadTrack(midifiletrk, firsttime, oo)) { throw new MidiFileException(); } } } //* check for empty trk containing midi events //* and for non-empty track that doesn't set chan/pan/vol //* (SONAR appears to put channel pan & vol on synth/audio trk) //if (FileStream.Summary) { //if (firsttime) { foreach (clsTrks.T trk in FileStream.OnCount.Next) { if (FileStream.OnCount[trk] > 0) { FileStream.SetChan(trk); } else { if (P.MMSW != null) { FileStream.CheckChan(trk); } } } //} MReaderFile.Close(); //if (FileStream.Keys.Keys.Count == 0) FileStream.Keys.Add(0, "major", 0); //if (!FileStream.Summary) FileStream.CreateData(NumTrks); FileStream.CreateData(oo, MaxMidiTicks); return(true); }