상속: MonoBehaviour
예제 #1
0
        private IEnumerator TriggerChecks(float time, int totalBeats)
        {
            const int freq = 16;

            for (var i = 0; i <= totalBeats; i++)
            {
                var total     = 0;
                var totalMiss = 0;
                for (var j = 0; j < freq; j++)
                {
                    // Check for accuracy
                    var ons       = _midiDeviceController.GetOnKeys();
                    var deltaTime = Time.time - startTime;
                    var eligible  = noteDurations.FindAll(e => e.start <= deltaTime && e.end >= deltaTime);
                    eligible.ForEach(e =>
                    {
                        total++;
                        if (!ons.Contains(PianoKeys.GetKeyFor(e.keyNum)))
                        {
                            totalMiss++;
                        }
                    });
                    yield return(new WaitForSeconds(time / freq));
                }

                piano.PutInstantFeedback(total, totalMiss, totalBeats);
            }
        }
예제 #2
0
        private Dictionary <int, List <MidiSegment> > MakeSegmentsFor(List <CompressedNoteDuration> userEvents,
                                                                      List <CompressedNoteDuration> trackEvents)
        {
            if (userEvents == null || trackEvents == null)
            {
                Debug.LogError("Null Args recved at MakeSegmentsFor()");
            }
            var segMap   = new Dictionary <int, List <MidiSegment> >();
            var trackMap = trackEvents.GroupBy(e => e.keyNum)
                           .ToDictionary(pianoKey => pianoKey.Key, notes => notes.ToList());
            var userMap = userEvents.GroupBy(e => e.keyNum).ToDictionary(pianoKey => pianoKey.Key, notes => notes.ToList());

            PianoKeys.GetAllKeys().Select(x => x.keyNum).Where(x => !trackMap.ContainsKey(x)).ToList()
            .ForEach(x => trackMap.Add(x, new List <CompressedNoteDuration>()));
            foreach (var item in trackMap)
            {
                var segments = new List <MidiSegment>();
                segMap[item.Key] = segments;
                item.Value.ForEach(e => segments.Add(new MidiSegment(MidiSegment.SegmentType.MISSED, e)));

                if (!userMap.ContainsKey(item.Key))
                {
                    continue;
                }

                foreach (var userSeg in userMap[item.Key])
                {
                    segments.Add(new MidiSegment(MidiSegment.SegmentType.EXTRA, userSeg));
                }

                item.Value.ForEach(e =>
                {
                    userMap[item.Key].ForEach(u =>
                    {
                        if (u.start >= e.start && u.end < e.end && u.start < e.end)
                        {
                            segments.Add(new MidiSegment(MidiSegment.SegmentType.CORRECT, e, u));
                        }
                        else if (u.start >= e.start && u.end > e.end && u.start < e.end)
                        {
                            segments.Add(new MidiSegment(MidiSegment.SegmentType.CORRECT, u, e));
                        }
                        else if (u.start <= e.start && u.end >= e.end)
                        {
                            segments.Add(new MidiSegment(MidiSegment.SegmentType.CORRECT, e));
                        }
                        else if (u.start <= e.start && u.end <= e.end && u.end > e.start)
                        {
                            segments.Add(new MidiSegment(MidiSegment.SegmentType.CORRECT, e, u));
                        }
                    });
                });
            }

            return(segMap);
        }
예제 #3
0
 /// <summary>
 /// Set offset for this page
 /// </summary>
 public void Scroll()
 {
     foreach (var item in
              from object item in PianoKeys.ItemsSource
              let key = item as KeyContext
                        where key.Value == PianoRollContext.TopKey
                        select item)
     {
         PianoKeys.ScrollTo(item);
     }
 }
예제 #4
0
 /// <summary>
 /// Initialize offset for this page
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void PianoKeys_OnLoaded(object sender, RoutedEventArgs e)
 {
     _pianoRollContext = this.DataContext as PianoRollContext;
     foreach (var item in
              from object item in PianoKeys.ItemsSource
              let key = item as KeyContext
                        where key.Value == PianoRollContext.TopKey
                        select item)
     {
         PianoKeys.ScrollTo(item);
         _cellWidth = (_items[item].ActualWidth * 4) / (5 * 16);
     }
 }
예제 #5
0
        private void handleChannelMsg(object sender, ChannelMessageEventArgs e)
        {
            var keyNum = e.Message.Data1;

            if (e.Message.Command == ChannelCommand.NoteOn)
            {
                PianoBuilder.instance.ActivateKey(keyNum, Color.green);

                notesOn.Add(PianoKeys.GetKeyFor(keyNum));
            }
            else if (e.Message.Command == ChannelCommand.NoteOff)
            {
                PianoBuilder.instance.DeactivateKey(keyNum);
                notesOn.Remove(PianoKeys.GetKeyFor(keyNum));
            }
        }
예제 #6
0
        private void Start()
        {
            PianoKeys.GetAllKeys().ForEach(e => { shouldKeyBeOn[e] = false; });
            piano                 = GetComponent <PianoBuilder>();
            crtHolder             = new List <Coroutine>();
            _midiDeviceController = GetComponent <MidiDeviceController>();
            scoreView             = GetComponent <ScoreView>();
            noteDurations         = new List <NoteDuration>();
            foreach (var item in PianoKeys.GetAllKeys())
            {
                pianoRollDict.Add(item, new List <GameObject>());
            }
            var ws = PianoKeys.GetAllKeys().Where(e => e.color == KeyColor.White).ToList();

            for (var i = 0; i < ws.Count(); i++)
            {
                colorDict[ws[i]] = MakeColorFromHex(0xffffff);
            }
            PianoKeys.GetAllKeys().Where(e => e.color == KeyColor.Black).ToList()
            .ForEach(e => colorDict[e] = MakeColorFromHex(0x0000ff));
        }
예제 #7
0
        public void SaveScoresAndViewFeedback(MidiSessionDto session, bool save = true)
        {
            var userEvents  = session.userNoteDurations;
            var trackEvents = session.trackNoteDurations;

            Debug.Log("User events: " + userEvents.Count());
            Debug.Log("Track events: " + trackEvents.Count());

            var segments = MakeSegmentsFor(userEvents, trackEvents);
            var velocity = 1f / session.velocityIn * session.noteScale;
            var total    = 0d;
            var correct  = 0d;

            if (userEvents.Count == 0)
            {
                Debug.LogWarning("No midievents recorded");
            }

            foreach (var e in segments)
            {
                var keyNum = e.Key;
                var list   = e.Value;

                foreach (var m in list)
                {
                    var key = PianoKeys.GetKeyFor(keyNum);
                    total++;
                    var go      = Instantiate(cube);
                    var lmraway = piano.GetLMRAwayVectorsForKey(key,
                                                                MidiFileSequencer.calcX(m.offsetY / velocity + m.scaleY / 2f / velocity));
                    spawnedSegments.Add(go);
                    var dummy = new GameObject();
                    var k     = piano.GetKeyObj(key);
                    dummy.transform.SetParent(k.transform);
                    go.transform.SetParent(piano.transform);
                    var dropdownScale = go.transform.localScale;
                    go.transform.localScale = new Vector3(dropdownScale.x, m.scaleY / velocity, dropdownScale.z);
                    go.transform.position   = lmraway.away;

                    Color color;
                    switch (m.type)
                    {
                    case MidiSegment.SegmentType.EXTRA:
                        color = Color.red;
                        go.transform.localScale += new Vector3(.0001f, .0001f, .0001f);
                        break;

                    case MidiSegment.SegmentType.CORRECT:
                        color = Color.green;
                        go.transform.localScale += new Vector3(.0002f, .0002f, .0002f);
                        correct++;
                        break;

                    case MidiSegment.SegmentType.MISSED:
                        color = Color.yellow;
                        break;

                    default:
                        color = Color.black;     // WTF C#??
                        break;
                    }

                    var rder = go.GetComponent <Renderer>();
                    rder.material.color = color;
                    var rotation = Quaternion.LookRotation(lmraway.centre - lmraway.away);
                    go.transform.rotation = rotation;
                    go.transform.Rotate(0, -90f, 90f);
                }
            }

            var accuracy = correct / total;

            Debug.Log("Displaying end feedback text");
            int score;

            if (save)
            {
                score = (int)(accuracy * 100);
            }
            else
            {
                score = (int)(session.Accuracy * 100);
            }
            piano.showText(session.FormattedTrackName + ": " + score + "%", 50, false);

            if (save) // dont resave a loaded session
            {
                Debug.Log("Saving session - score = " + accuracy * 100);
                // Same but update accuracy
                var midiSessionDTO = new MidiSessionDto(RuntimeSettings.MIDI_FILE_NAME, accuracy, userEvents,
                                                        session.trackNoteDurations, session.noteScale, session.velocityIn, session.offsetStartTime);
                new MidiSessionController().putMidiSession(midiSessionDTO);
            }
        }
예제 #8
0
        private List <CompressedNoteDuration> ConvertToNoteDurationFromMidiEventStorage(List <MidiEventStorage> midiEvents)
        {
            var list = new List <CompressedNoteDuration>();

            while (midiEvents.Count() > 0)
            {
                // Until we have an empty list, keep searching notes and end of it
                if (midiEvents.Count == 0)
                {
                    break;
                }
                var head = midiEvents.First();
                if (head.isEnd)
                {
                    Debug.LogError("Unexpected end of note");
                }
                var keyNum = head.keyNum;
                for (var i = 1; i < midiEvents.Count(); i++)
                {
                    if (midiEvents[i].keyNum == keyNum)
                    {
                        if (!midiEvents[i].isEnd)
                        {
                            Debug.LogError("Double Start of a note");
                            return(list);
                        }

                        var item = midiEvents[i];
                        list.Add(new CompressedNoteDuration(head.time, item.time - head.time, PianoKeys.GetKeyFor(keyNum)));
                        midiEvents.Remove(head);
                        midiEvents.Remove(item);
                        break;
                    }
                }
            }

            return(list);
        }
예제 #9
0
        public void Update()
        {
            if (RuntimeSettings.LOAD_SAVED_SESSION_AT_STARTUP)
            {
                Debug.Log("Loading a saved session");
                RuntimeSettings.LOAD_SAVED_SESSION_AT_STARTUP = false;
                scoreView.SaveScoresAndViewFeedback(RuntimeSettings.CACHED_SESSION, false);
                RuntimeSettings.CACHED_SESSION = null;
                ClearPianoRoll();
                startTime = -1f;
            }

            if (startTime < 0f)
            {
                return;
            }
            var deltaT = Time.time - startTime;

            var minDistDict = new Dictionary <PianoKey, float>();

            foreach (var i in PianoKeys.GetAllKeys())
            {
                minDistDict[i] = 2f;
            }
            noteDurations.ForEach(note =>
            {
                if (!note.hasKeyBeenActivated && deltaT >= note.start - note.duration && deltaT < note.end - note.duration)
                {
                    piano.ActivateKey(note.keyNum, Color.red, note.duration);
                    note.hasKeyBeenActivated = true;
                }

                if (deltaT >= note.start - note.duration && deltaT < note.end - note.duration)
                {
                    minDistDict[PianoKeys.GetKeyFor(note.keyNum)] = 0;
                    return;
                }

                if (deltaT > note.end)
                {
                    return;
                }

                if (deltaT >= note.start - 2f && deltaT <= note.start)
                {
                    minDistDict[PianoKeys.GetKeyFor(note.keyNum)] = Mathf.Min(Mathf.Abs(note.start - deltaT),
                                                                              minDistDict[PianoKeys.GetKeyFor(note.keyNum)]);
                }
            });
            foreach (var item in minDistDict)
            {
                float h, s, v;
                Color.RGBToHSV(colorDict[item.Key], out h, out s, out v);
                if (item.Value == 2f)
                {
                    s = 0f;
                }
                else
                {
                    s = (2 - item.Value) / 2 * s;
                }
                var newc = Color.HSVToRGB(h, s, v);
                newc.a = (2 - item.Value) / 2;
                if (newc.a >= 1f)
                {
                    shouldKeyBeOn[item.Key] = true;
                }
                else
                {
                    shouldKeyBeOn[item.Key] = false;
                }
                piano.UpdateDiskColor(item.Key, newc);
            }

            if (noteDurations.Last().hasKeyBeenActivated || Input.GetKeyDown(KeyCode.Escape))
            {
                scoreView.ConvertEventsSaveScoresAndViewFeedback(_midiDeviceController.GetMidiEvents(),
                                                                 noteDurations.Select(x => new CompressedNoteDuration(x)).ToList(), notesScale,
                                                                 RuntimeSettings.GAME_SPEED, startTime);
                ClearPianoRoll();
                startTime = -1f;
            }

            if (gameStarted)
            {
                var step = RuntimeSettings.GAME_SPEED * Time.deltaTime;
                foreach (var item in pianoRollDict)
                {
                    if (item.Value.Count == 0)
                    {
                        continue;
                    }
                    var lmr = piano.GetLMRAwayVectorsForKey(item.Key);
                    foreach (var obj in item.Value)
                    {
                        obj.transform.Translate(0, -step, 0);
                        if (obj.transform.childCount > 0)
                        {
                            var co         = obj.transform.GetChild(0);
                            var childScale = co.transform.localScale;
                            var mag        = (obj.transform.position - lmr.centre).magnitude;
                            if (mag < childScale.y)
                            {
                                var cs = co.transform.localScale.y;

                                obj.transform.localScale = new Vector3(1f, mag / cs, 1f);
                            }

                            if (mag < 0.01f)
                            {
                                DestroyImmediate(co.gameObject);
                            }
                        }
                    }
                }

                foreach (var obj in fineLines)
                {
                    var center     = PianoKeys.GetKeyFor(PianoBuilder.CENTRE);
                    var centerAway = keyAwayDir[center];
                    obj.transform.position =
                        Vector3.MoveTowards(obj.transform.position, centerAway.transform.position, step);
                }
            }
        }
예제 #10
0
        private void SpawnNotesDropDown(List <Note> notes)
        {
            Debug.Log("Spawning piano roll notes");
            ClearPianoRoll();
            notes.ForEach(e =>
            {
                var number = e.NoteNumber;
                float y;
                var key = PianoKeys.GetKeyFor(number);
                if (key == null)
                {
                    return;
                }
                var startMusical  = (MusicalTimeSpan)e.TimeAs(TimeSpanType.Musical, tempoMapManager.TempoMap);
                var lengthMusical = e.LengthAs(TimeSpanType.Musical, tempoMapManager.TempoMap);
                y              = (float)startMusical.Numerator / startMusical.Denominator * notesScale;
                var delta      = (MusicalTimeSpan)lengthMusical;
                var scale      = (float)delta.Numerator / delta.Denominator * notesScale;
                var lmraway    = piano.GetLMRAwayVectorsForKey(key);
                var obj        = Instantiate(pianoRollObject);
                var dummy      = new GameObject("dummy");
                var awayVector = lmraway.away;
                var lmraway2   = piano.GetLMRAwayVectorsForKey(key, calcX(y + scale / 2f));
                var lmraway3   = piano.GetLMRAwayVectorsForKey(key, calcX(y + scale));
                if (!keyAwayDir.ContainsKey(key))
                {
                    var newO = new GameObject();
                    newO.transform.position = piano.GetLMRAwayVectorsForKey(key, -1).away;
                    newO.transform.SetParent(piano.GetKeyObj(key).transform);
                    keyAwayDir[key] = newO;
                }

                var keyPos = lmraway.centre;
                dummy.transform.position = lmraway3.away;
                dummy.transform.rotation = Quaternion.LookRotation(keyPos - awayVector);
                dummy.transform.Rotate(0, -90f, 90f);
                dummy.transform.SetParent(piano.transform);
                obj.transform.SetParent(dummy.transform);
                pianoRollObjects.Add(obj);
                var dropdownScale        = obj.transform.localScale;
                obj.transform.localScale = new Vector3(dropdownScale.x, scale, dropdownScale.z);
                var rotation             = Quaternion.LookRotation(keyPos - awayVector);
                obj.transform.rotation   = rotation;
                obj.transform.Rotate(0, -90f, 90f);
                obj.transform.position = lmraway2.away;

                var rendererObj            = obj.GetComponent <Renderer>();
                rendererObj.material.color = colorDict[key];

                var expectTime = ((lmraway2.away - keyPos).magnitude + scale / 2) / RuntimeSettings.GAME_SPEED;
                var expectEnd  = scale / RuntimeSettings.GAME_SPEED;

                pianoRollDict[key].Add(dummy);
                noteDurations.Add(new NoteDuration(expectTime, expectEnd, key));
            });

            // Spawn fine lines (horizontal)
            var lastNoteMusicalStart =
                (MusicalTimeSpan)notes.Last().TimeAs(TimeSpanType.Musical, tempoMapManager.TempoMap);
            var lastNoteMusicalLen =
                (MusicalTimeSpan)notes.Last().LengthAs(TimeSpanType.Musical, tempoMapManager.TempoMap);
            var lastNoteMuscialEnd = lastNoteMusicalStart + lastNoteMusicalLen;

            var lastBeatY = (float)lastNoteMuscialEnd.Numerator / lastNoteMusicalLen.Denominator * notesScale;
            var beatDelta = 1f * notesScale;

            var midKey      = PianoKeys.GetKeyFor(PianoBuilder.CENTRE);
            var totalBeatsI = (int)(lastBeatY / beatDelta);

            for (var i = 1; i <= totalBeatsI; i++)
            {
                var line  = Instantiate(fineLine);
                var v     = piano.GetLMRAwayVectorsForKey(midKey, calcX(beatDelta * i));
                var dummy = new GameObject("dummy Fineline");
                dummy.transform.position = v.away;
                dummy.transform.SetParent(piano.GetKeyObj(midKey).transform);
                line.transform.SetParent(dummy.transform);
                line.transform.position = v.away;
                var rotation = Quaternion.LookRotation(v.centre - v.away);
                line.transform.rotation = rotation;
                line.transform.Rotate(0, 0f, 90f);
                fineLines.Add(dummy);
            }

            timeBetweenBeats = beatDelta / RuntimeSettings.GAME_SPEED;
            totalBeats       = totalBeatsI;
        }