예제 #1
0
    static private void ReadTrack()
    {
        MIDITrack track = new MIDITrack();

        track.events = new List <MIDIEvent>();

        string trackChunkType = ReadString(4);

        if (!trackChunkType.Equals("MTrk"))
        {
            throw new System.FormatException("No track chunk type has been found.");
        }

        int trackChunkLength = ReadInt32();

        uint trackChunkEnd         = m_index + (uint)trackChunkLength;
        int  accumulatedDeltaTicks = 0;

        m_prevStatus = 0;
        while (m_index < trackChunkEnd)
        {
            int deltaTicks = ReadVariableLengthInt();
            accumulatedDeltaTicks += deltaTicks;
            m_status = ReadByte();

            MIDIEvent midiEvent = ReadEvent(accumulatedDeltaTicks);
            if (midiEvent != null)
            {
                track.events.Add(midiEvent);
                accumulatedDeltaTicks = 0;
            }
        }

        m_song.tracks.Add(track);
    }
예제 #2
0
        /// <summary>
        /// MIDIデータに歌詞を追加します。
        /// </summary>
        private void MakeLyric(MIDITrack midiTrack, List <MeasureAndTextBox> measures)
        {
            RemoveLyric(midiTrack);

            foreach (MeasureAndTextBox measure in measures)
            {
                StringBuilder stringBuilder = new StringBuilder(measure.Lyric);
                for (int i = 0; i < measure.MidiEvent.Length; i++)
                {
                    if (stringBuilder.Length <= 0)
                    {
                        break;
                    }
                    string lyricChar = stringBuilder[0].ToString();                     //先頭の文字を取得
                    stringBuilder.Remove(0, 1);                                         //先頭の文字を削除
                    //次の文字が小文字の場合、一緒に歌詞に含める。
                    if (IsFirstCharacterLowerCase(stringBuilder.ToString()))
                    {
                        lyricChar += stringBuilder[0].ToString();                           //先頭の文字を追加
                        stringBuilder.Remove(0, 1);                                         //先頭の文字を削除
                    }

                    MIDIEvent targetEvent = measure.MidiEvent[i];
                    MIDIEvent lyricEvent  = MIDIEvent.CreateLyric(targetEvent.Time, lyricChar);
                    midiTrack.InsertEventAfter(lyricEvent, targetEvent);
                }
            }
        }
예제 #3
0
        static void AnalyzeTrack(MIDITrack track)
        {
            foreach (IMIDIEvent lEvent in track.Events)
            {
                switch (lEvent.Type)
                {
                case MIDIEventType.NoteOn:
                    MIDIChannelEvent cEvent = (MIDIChannelEvent)lEvent;
                    Console.WriteLine($"Note on: {cEvent.Data1}");
                    break;

                case MIDIEventType.Meta:
                    MIDIMetaEvent mEvent = (MIDIMetaEvent)lEvent;
                    if (mEvent.MetaType == 3)
                    {
                        Console.WriteLine($"Track name: {Encoding.ASCII.GetString(mEvent.Data)}");
                    }
                    if (mEvent.MetaType == 4)
                    {
                        Console.WriteLine($"Instrument: {Encoding.ASCII.GetString(mEvent.Data)}");
                    }
                    break;
                }
            }
        }
예제 #4
0
        public void TestRead()
        {
            midi.Read(TestUtils.GetResourceStream("Bass_sample.mid"));
            Assert.AreEqual(2, midi.TrackCount);

            int i = 0;
            List <MIDIEvent> events = new List <MIDIEvent>();

            MIDITrack track0 = midi.Tracks[0];

            Assert.AreEqual(4, track0.EventCount);
            events.Clear();
            events.AddRange(track0.GetAllEvents());
            Assert.AreEqual(0, events[0].Time);
            Assert.AreEqual(MIDIMessageType.TimeSignature, events[0].Data.Type);
            Assert.AreEqual(4, (events[0].Data as MIDITimeSignatureMessage).Numerator);
            Assert.AreEqual(4, (events[0].Data as MIDITimeSignatureMessage).Denominator);
            Assert.AreEqual(24, (events[0].Data as MIDITimeSignatureMessage).MetronomeClocks);
            Assert.AreEqual(8, (events[0].Data as MIDITimeSignatureMessage).NotatedQuarterTicks);

            Assert.AreEqual(0, events[1].Time);
            Assert.AreEqual(MIDIMessageType.SetTempo, events[1].Data.Type);
            Assert.AreEqual(500000, (events[1].Data as MIDITempoMessage).Tempo);
            Assert.That((events[1].Data as MIDITempoMessage).BeatsPerMinute, Is.EqualTo(120).Within(0.001));

            MIDITrack track1 = midi.Tracks[1];

            Assert.AreEqual(31, track1.EventCount);
            events.Clear();
            events.AddRange(track1.GetAllEvents());
            Assert.AreEqual(0, events[0].Time);
            Assert.AreEqual(MIDIMessageType.ProgramChange, events[0].Data.Type);
            Assert.AreEqual(0x21, (events[0].Data as MIDIProgramChangeMessage).Program);
            Assert.AreEqual(0, events[1].Time);
            Assert.AreEqual(MIDIMessageType.ControlChange, events[1].Data.Type);
            Assert.AreEqual(MIDIControl.ChannelVolumeMSB, (events[1].Data as MIDIControlChangeMessage).Controller);

            Assert.AreEqual(0, events[2].Time);
            Assert.AreEqual(129, events[3].Time);
            Assert.AreEqual(360, events[4].Time);
            Assert.AreEqual(480, events[5].Time);
            Assert.AreEqual(483, events[6].Time);
            Assert.AreEqual(600, events[7].Time);
            Assert.AreEqual(3450, events[29].Time);

            Assert.AreEqual(MIDIMessageType.NoteOn, events[2].Data.Type);
            Assert.AreEqual(MIDIMessageType.NoteOff, events[3].Data.Type);
            Assert.AreEqual(MIDIMessageType.NoteOff, events[29].Data.Type);

            Assert.AreEqual(0, (events[2].Data as MIDINoteMessage).Channel);

            Assert.AreEqual(0x2D, (events[2].Data as MIDINoteMessage).Key);
            Assert.AreEqual(0x2D, (events[3].Data as MIDINoteMessage).Key);
            Assert.AreEqual(0x32, (events[22].Data as MIDINoteMessage).Key);
        }
예제 #5
0
    public void ReadMIDIFile(string path)
    {
        Debug.Log(path);

        this.midiFile = File.OpenRead(path);
        this.header   = ParseHeader(midiFile);

        this.tracks       = new List <MIDITrack>();
        this.currentNotes = new Dictionary <uint, MIDINote>();
        for (int i = 0; i < header.number_of_tracks; i++)
        {
            MIDITrack track = ParseTrack(midiFile);
            this.tracks.Add(track);
        }
    }
예제 #6
0
        /// <summary>
        /// MIDIデータから歌詞を削除します。
        /// </summary>
        public void RemoveLyric(MIDITrack midiTrack)
        {
            List <MIDIEvent> lyricEvents = new List <MIDIEvent>();

            //ループ中にイベントを除外又は削除してはならない。イベントの消滅により次のイベントが探索できなくなるからだ。
            foreach (MIDIEvent midiEvent in midiTrack)
            {
                if (midiEvent.IsLyric)
                {
                    lyricEvents.Add(midiEvent);
                }
            }

            foreach (MIDIEvent midiEvent in lyricEvents)
            {
                midiTrack.RemoveEvent(midiEvent);
            }
        }
    private void Reset()
    {
        if (m_song == null)
        {
            return;
        }

        m_elapsedTime            = -m_song.firstMeasureDuration;
        m_score                  = 0;
        m_totalNoteCount         = 0;
        m_correctNoteCount       = 0;
        m_hitStreak              = 0;
        m_multiplier             = 1.0f;
        m_leftHandSongNoteIndex  = 0;
        m_rightHandSongNoteIndex = 0;
        m_leftHandSongNotes.Clear();
        m_rightHandSongNotes.Clear();

        for (int i = 0; i < m_song.tracks.Count; i++)
        {
            MIDITrack track = m_song.tracks[i];
            foreach (MIDIEvent midiEvent in track.events)
            {
                if (midiEvent.GetType() == typeof(MIDINoteEvent))
                {
                    MIDINoteEvent noteEvent = midiEvent as MIDINoteEvent;
                    if (noteEvent.isNoteOn)
                    {
                        if (i == 1)
                        {
                            m_leftHandSongNotes.Add(noteEvent);
                        }
                        else if (i == 0)
                        {
                            m_rightHandSongNotes.Add(noteEvent);
                        }
                    }
                }
            }
        }

        m_deviceNoteTimestamps.Clear();
    }
예제 #8
0
    static private void ForwardMinNextEvent(MIDIEvent minNextEvent, List <MIDIEvent> nextEventList)
    {
        for (int i = 0; i < m_song.tracks.Count; i++)
        {
            MIDITrack track          = m_song.tracks[i];
            int       nextEventIndex = track.events.IndexOf(minNextEvent);
            if (nextEventIndex == -1)
            {
                continue;
            }

            nextEventList[i] = null;
            nextEventIndex++;
            if (nextEventIndex < track.events.Count)
            {
                nextEventList[i] = track.events[nextEventIndex];
            }
        }
    }
예제 #9
0
    // Use this for initialization
    void Start()
    {
        midi = GetComponent <MIDI>();
        midi.ReadMIDIFile(midiFilePath);

        int trackCount = midi.tracks.Count;

        if (generateOnlyFromFirstTrack)
        {
            trackCount = 1;
        }

        for (int i = 0; i < trackCount; i++)
        {
            MIDITrack track = midi.tracks[i];
            foreach (MIDIEvent e in track.events)
            {
                Debug.Log("type of event" + e.GetType().ToString());
                if (e.GetType() != typeof(MIDINote))
                {
                    continue;
                }


                MIDINote   note = (MIDINote)e;
                GameObject platform;
                if (this.platforms.Length > 0)
                {
                    int idx = Random.Range(0, this.platforms.Length);
                    platform = GameObject.Instantiate(this.platforms[idx]) as GameObject;
                }
                else
                {
                    platform = GameObject.CreatePrimitive(PrimitiveType.Cube);
                }


                Vector3 pos = new Vector3(note.absoluteStartTime, (float)note.note, 0.0f);
                platform.transform.position = pos;
            }
        }
    }
예제 #10
0
    private void PrepareNextEventIndexList()
    {
        for (int i = 0; i < m_song.tracks.Count; i++)
        {
            MIDITrack track = m_song.tracks[i];

            for (int j = 0; j < track.events.Count; j++)
            {
                if (track.events[j].timestamp >= m_elapsedTime - 0.001f)
                {
                    m_nextEventIndexList[i] = j;
                    break;
                }
                else
                {
                    m_nextEventIndexList[i] = track.events.Count;
                }
            }
        }
    }
예제 #11
0
    void OnGUI()
    {
        if (GUI.Button(new Rect(10, 70, 120, 30), "Play"))
        {
            AudioSource audioSrc = GetComponent <AudioSource>();

            MIDITrack track = midi.tracks[0];
            foreach (MIDIEvent e in track.events)
            {
                Debug.Log("type of event" + e.GetType().ToString());
                if (e.GetType() != typeof(MIDINote))
                {
                    continue;
                }


                MIDINote note = (MIDINote)e;
                Debug.Log("note:" + note.note);
                audioSrc.clip = sampler.samples[note.note];
                audioSrc.PlayScheduled((double)note.absoluteStartTime);
            }
        }
    }
예제 #12
0
    public void Update(float deltaTime)
    {
        if (m_isPlaying && !m_isSleeping)
        {
            deltaTime = deltaTime * m_speedFactor;
            NotifyUpdate(deltaTime);

            m_elapsedTime += deltaTime;
            CalcCurrentMeasure();

            for (int i = 0; i < m_song.tracks.Count; i++)
            {
                MIDITrack track = m_song.tracks[i];

                bool processedAllEventsWithCurrentTimestamp = false;
                while (!processedAllEventsWithCurrentTimestamp)
                {
                    int nextEventIndex = m_nextEventIndexList[i];
                    if (nextEventIndex >= track.events.Count)
                    {
                        break;
                    }

                    MIDIEvent nextEvent = track.events[nextEventIndex];
                    if (nextEvent.timestamp <= m_elapsedTime)
                    {
                        NotifyEvent(nextEvent, i);
                        m_nextEventIndexList[i]++;
                    }
                    else
                    {
                        processedAllEventsWithCurrentTimestamp = true;
                    }
                }
            }
        }
    }
예제 #13
0
        public void TestRead()
        {
            midi.ReadHMP(TestUtils.GetResourceStream("vgame20.hmp"));
            Assert.AreEqual(13, midi.TrackCount);
            Assert.AreEqual(HMPValidDevice.Default, midi.Tracks[0].HMPDevices);
            for (int i = 1; i < midi.TrackCount; ++i)
            {
                Assert.AreEqual(HMPValidDevice.All, midi.Tracks[i].HMPDevices);
            }
            foreach (MIDITrack track in midi.Tracks)
            {
                Assert.AreEqual(0, track.HMPBranchPoints.Count);
            }

            List <MIDIEvent> events = new List <MIDIEvent>();
            MIDITrack        track1 = midi.Tracks[1];

            Assert.AreEqual(2952, track1.EventCount);
            events.Clear();
            events.AddRange(track1.GetAllEvents());
            Assert.AreEqual(0, events[2].Time);
            Assert.AreEqual(5743, events[120].Time);
            Assert.AreEqual(5977, events[300].Time);
        }
예제 #14
0
    MIDITrack ParseTrack(FileStream inFile)
    {
        MIDITrack track = new MIDITrack();

        // MThd
        {
            byte[] _mtrk = new byte[4];
            inFile.Read(_mtrk, 0, 4);
            Array.Reverse(_mtrk);
            track.MTrk = BitConverter.ToUInt32(_mtrk, 0);
            if(track.MTrk != (UInt32)MIDI_EVENT_TYPES.TRACK_CHUNK_ID){
                throw new Exception("wrong track header");
            }
        }

        // track length
        {
            byte[] _len = new byte[4];
            inFile.Read(_len, 0, 4);
            Array.Reverse(_len);
            track.track_length = BitConverter.ToUInt32(_len, 0);
        }

        // start reading events
        long pos = inFile.Position;
        this.timeOffset = 0;
        while(inFile.Position < pos + track.track_length){
            int deltaTime = ParseVarLen(inFile);
            this.timeOffset += deltaTime;

            MIDIEvent midi_event = new MIDIEvent();
            midi_event.delta_time = deltaTime;
            midi_event.event_type = inFile.ReadByte();

            switch(midi_event.event_type){
            case (int)MIDI_EVENT_TYPES.META_EVENT:
                ParseMetaEvent(inFile, midi_event);
        //				Debug.Log("Meta event");
                break;
            case (int)MIDI_EVENT_TYPES.SYSEX_EVENT:
            case (int)MIDI_EVENT_TYPES.SYSEX_CHUNK:
                ParseSysexEvent(inFile, midi_event);
        //				Debug.Log("Sysex event");
                break;
            default:
                midi_event = ParseChannelEvent(inFile, midi_event);
        //				Debug.Log("channel event");
                break;
            }

            Debug.Log(midi_event);
            track.events.Add(midi_event);

        }

        return track;
    }
예제 #15
0
 public byte[] ProcessMessage(MIDITrack track, int messageIndex)
 {
     return(track.MidiEvents[messageIndex].MidiMessage);
 }
예제 #16
0
    private void ShowNotesInVisibleRegion(float startTimeOfVisibleRegion, float endTimeOfVisibleRegion)
    {
        for (int i = 0; i < m_noteObjectsRingBuffer.GetSize(); i++)
        {
            GameObject noteObject = m_noteObjectsRingBuffer.GetCurrentElement();
            m_noteObjectsRingBuffer.Advance();
            noteObject.transform.localPosition = new Vector3(0.0f, 0.0f, -10.0f);
            noteObject.transform.localScale    = new Vector3(0.1f, 0.1f, 0.1f);
        }

        List <MIDINoteEvent> pressedNoteEvents = new List <MIDINoteEvent>();

        for (int i = 0; i < m_song.tracks.Count; i++)
        {
            if (!m_isRightHandEnabled && i == 0)
            {
                continue;
            }

            if (!m_isLeftHandEnabled && i == 1)
            {
                continue;
            }

            MIDITrack track = m_song.tracks[i];
            foreach (MIDIEvent midiEvent in track.events)
            {
                if (midiEvent.GetType() == typeof(MIDINoteEvent))
                {
                    MIDINoteEvent noteEvent = midiEvent as MIDINoteEvent;

                    if (noteEvent.isNoteOn &&
                        noteEvent.timestamp >= startTimeOfVisibleRegion - 5.0f &&
                        noteEvent.timestamp <= endTimeOfVisibleRegion + 5.0f)
                    {
                        pressedNoteEvents.Add(noteEvent);
                    }
                    else if (!noteEvent.isNoteOn &&
                             noteEvent.timestamp >= startTimeOfVisibleRegion - 5.0f &&
                             noteEvent.timestamp <= endTimeOfVisibleRegion + 5.0f)
                    {
                        MIDINoteEvent releasedNoteEvent = noteEvent;
                        foreach (MIDINoteEvent pressedNoteEvent in pressedNoteEvents)
                        {
                            if (pressedNoteEvent.note == releasedNoteEvent.note)
                            {
                                if (releasedNoteEvent.timestamp < pressedNoteEvent.timestamp)
                                {
                                    break;
                                }

                                pressedNoteEvents.Remove(pressedNoteEvent);

                                GameObject noteObject = m_noteObjectsRingBuffer.GetCurrentElement();
                                m_noteObjectsRingBuffer.Advance();

                                float startX, startY, startZ, endX, endY, endZ;

                                startZ = (pressedNoteEvent.timestamp - startTimeOfVisibleRegion) * m_defaultSpeed;
                                endZ   = (releasedNoteEvent.timestamp - startTimeOfVisibleRegion) * m_defaultSpeed;

                                float offset = GetNoteOffset(noteEvent.note, m_octavePitch);
                                if (IsBlackNote(noteEvent.note))
                                {
                                    startX = offset * m_noteWidth + 0.0015f;
                                    endX   = (offset + 0.5f) * m_noteWidth - 0.0015f;

                                    startY = 0.0f - 0.059f;
                                    endY   = 0.0121f - 0.059f;
                                }
                                else
                                {
                                    startX = offset * m_noteWidth;
                                    endX   = (offset + 1.0f) * m_noteWidth;

                                    startY = 0.0f - 0.059f;
                                    endY   = m_noteHeight - 0.059f;
                                }

                                noteObject.transform.localPosition = new Vector3((startX + endX) * 0.5f, (startY + endY) * 0.5f, (startZ + endZ) * 0.5f);
                                noteObject.transform.localScale    = new Vector3(Mathf.Abs(endX - startX), Mathf.Abs(endY - startY), Mathf.Abs(endZ - startZ));

                                // determine vertex colors
                                Color color = Color.HSVToRGB((float)i / (float)m_song.tracks.Count, 1.0f, 1.0f);
                                if (IsBlackNote(noteEvent.note))
                                {
                                    color *= 0.5f;
                                }

                                Mesh      mesh          = noteObject.GetComponent <MeshFilter>().mesh;
                                Vector3[] vertPositions = mesh.vertices;
                                Color[]   vertColors    = new Color[vertPositions.Length];
                                for (int j = 0; j < vertPositions.Length; j++)
                                {
                                    float t = vertPositions[j].z + 0.5f;
                                    vertColors[j] = Color.Lerp(color, color * 0.5f, t);
                                }
                                mesh.colors = vertColors;

                                break;
                            }
                        }
                    }
                }
            }
        }
    }
예제 #17
0
    MIDITrack ParseTrack(FileStream inFile)
    {
        MIDITrack track = new MIDITrack();


        // MThd
        {
            byte[] _mtrk = new byte[4];
            inFile.Read(_mtrk, 0, 4);
            Array.Reverse(_mtrk);
            track.MTrk = BitConverter.ToUInt32(_mtrk, 0);
            if (track.MTrk != (UInt32)MIDI_EVENT_TYPES.TRACK_CHUNK_ID)
            {
                throw new Exception("wrong track header");
            }
        }

        // track length
        {
            byte[] _len = new byte[4];
            inFile.Read(_len, 0, 4);
            Array.Reverse(_len);
            track.track_length = BitConverter.ToUInt32(_len, 0);
        }

        // start reading events
        long pos = inFile.Position;

        this.timeOffset = 0;
        while (inFile.Position < pos + track.track_length)
        {
            int deltaTime = ParseVarLen(inFile);
            this.timeOffset += deltaTime;


            MIDIEvent midi_event = new MIDIEvent();
            midi_event.delta_time = deltaTime;
            midi_event.event_type = inFile.ReadByte();

            switch (midi_event.event_type)
            {
            case (int)MIDI_EVENT_TYPES.META_EVENT:
                ParseMetaEvent(inFile, midi_event);
//				Debug.Log("Meta event");
                break;

            case (int)MIDI_EVENT_TYPES.SYSEX_EVENT:
            case (int)MIDI_EVENT_TYPES.SYSEX_CHUNK:
                ParseSysexEvent(inFile, midi_event);
//				Debug.Log("Sysex event");
                break;

            default:
                midi_event = ParseChannelEvent(inFile, midi_event);
//				Debug.Log("channel event");
                break;
            }

            Debug.Log(midi_event);
            track.events.Add(midi_event);
        }


        return(track);
    }
예제 #18
0
        private void ExecuteButton_Click(object sender, RoutedEventArgs e)
        {
            OutputStackPanel.Children.Clear();
            Measures.Clear();

            if (!File.Exists(MidiFileName))
            {
                return;
            }

            try
            {
                MidiData = new MIDIData(MidiFileName);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }

            if (MidiData.TimeMode != MIDIData.TimeModes.TPQN)
            {
                MessageBox.Show("TPQN以外の形式には対応していません。", "エラー", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            MIDITrack track = TargetTrack;

            if (track == null)
            {
                MessageBox.Show("未対応のフォーマットです。\n対応フォーマットは「Format0」と「Format1」です。", "エラー", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            //結合できるイベントを結合
            foreach (MIDIEvent midiEvent in track)
            {
                if (midiEvent.IsNoteOn)            //ノートONで
                {
                    if (!midiEvent.IsCombined)     //結合されていない場合
                    {
                        midiEvent.Combine();
                    }
                }
            }

            int currentMeasure      = -1;
            List <MIDIEvent> events = new List <MIDIEvent>();                         //一小節分のノートイベントを保管する。

            //ノートのある小節の個数分、テキストボックス追加
            foreach (MIDIEvent midiEvent in track)
            {
                if (midiEvent.IsNoteOn)
                {
                    int measure = MidiData.BreakTime(midiEvent.Time).Measure;       //このノートの所属している小節取得
                    if (measure > currentMeasure)                                   //次の小節に行ったら
                    {
                        if (events.Count != 0)                                      //小節へイベントの追加、その後クリア
                        {
                            Measures.Last().MidiEvent = events.ToArray();
                            events.Clear();
                        }

                        TextBox textBox = AddTextBox(measure);                      //ここで作成しないと、小節番号がわからない。
                        Measures.Add(new MeasureAndTextBox(textBox));

                        events.Add(midiEvent);

                        currentMeasure = measure;
                    }
                    else
                    {
                        events.Add(midiEvent);
                    }
                }
            }
            //最後のイベント追加
            if (events.Count != 0)
            {
                Measures.Last().MidiEvent = events.ToArray();
                events.Clear();
            }

            SaveButton.IsEnabled = true;
        }