Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recording to DanceData form Kinect or File. #30

Merged
merged 3 commits into from
Dec 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5,654 changes: 5,654 additions & 0 deletions unity/Assets/RecordingScene.unity

Large diffs are not rendered by default.

130 changes: 96 additions & 34 deletions unity/Assets/Scripts/DanceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using UnityEngine;
using System.IO;
using System.Linq;
using UnityEngine.SceneManagement;

namespace PoseTeacher
{
Expand All @@ -13,6 +14,7 @@ public class DanceManager : MonoBehaviour

PoseGetter selfPoseInputGetter;

public EndScoreScreen endScoreScreen;
public GameObject videoCube;
public DancePerformanceScriptableObject DancePerformanceObject;

Expand All @@ -30,10 +32,11 @@ public class DanceManager : MonoBehaviour
private AudioClip song;
private AudioSource audioSource;

readonly List<(float, DanceData)> goals = new List<(float,DanceData)>();
List<(float, DanceData)> goals = new List<(float,DanceData)>();

public float songTime => audioSource?.time ?? 0;

bool finished = false;
int currentId = 0;

public void Awake()
Expand All @@ -46,51 +49,43 @@ public void Awake()
{
Instance = this;
}

/* For checking if calibration worked, testing only
GameObject calobjs = GameObject.Instantiate(Resources.Load<GameObject>("CalibrationObjects"));
calobjs.transform.Find("Player").transform.position = PersistentData.Instance.playerPosition;
calobjs.transform.Find("Kinect").transform.position = PersistentData.Instance.kinectPosition;
calobjs.transform.Find("Teacher").transform.position = PersistentData.Instance.teacherPositions[0];
*/
}

// Start is called before the first frame update
// Start is called before the first frame update
public void Start()
{
avatarListSelf = new List<AvatarContainer>();
avatarListTeacher = new List<AvatarContainer>();
avatarListSelf.Add(new AvatarContainer(avatarContainerSelf));
avatarListTeacher.Add(new AvatarContainer(avatarContainerTeacher));

audioSource = GetComponent<AudioSource>();
song = DancePerformanceObject.SongObject.SongClip;
audioSource.clip = song;
danceData = DancePerformanceObject.danceData.LoadDanceDataFromScriptableObject();

for(int i = 0; i < DancePerformanceObject.goals.Count; i++)
{
goals.Add((DancePerformanceObject.goalStartTimestamps[i], DancePerformanceObject.goals[i]));
}

selfPoseInputGetter = getPoseGetter(selfPoseInputSource);

audioSource.Play();
Setup();
RestartSong();
}

// Update is called once per frame
public void Update()
{
float timeOffset = audioSource.time - danceData.poses[currentId].timestamp;
currentSelfPose = selfPoseInputGetter.GetNextPose();
AnimateSelf(currentSelfPose);
if (goals.Count > 0 && audioSource.time >= goals[0].Item1)
if (!finished)
{
ScoringManager.Instance.StartNewGoal(goals[0].Item2.poses, 0f);
goals.RemoveAt(0);
}
AnimateTeacher(danceData.GetInterpolatedPose(currentId, out currentId, timeOffset).toPoseData());

if (audioSource.time > danceData.poses[danceData.poses.Count - 1].timestamp)
{
audioSource.Stop();
List<Scores> finalScores = ScoringManager.Instance.getFinalScores();
Debug.Log(finalScores);
//TODO: Add final score screen
float timeOffset = audioSource.time - danceData.poses[currentId].timestamp;
if (goals.Count > 0 && audioSource.time >= goals[0].Item1)
{
ScoringManager.Instance.StartNewGoal(goals[0].Item2.poses, 0f);
goals.RemoveAt(0);
}
AnimateTeacher(danceData.GetInterpolatedPose(currentId, out currentId, timeOffset).toPoseData());

if (audioSource.time >= audioSource.clip.length)
{
FinishSong();
}
}

}

public void OnApplicationQuit()
Expand Down Expand Up @@ -127,5 +122,72 @@ PoseGetter getPoseGetter(InputSource src) {
return new FilePoseGetter(true) { ReadDataPath = fake_file };
}
}

void FinishSong()
{
finished = true;
audioSource.Stop();
int totalScore = ScoringManager.Instance.getFinalScores().Item1;
List<Scores> finalScores = ScoringManager.Instance.getFinalScores().Item2;

endScoreScreen.setValues(totalScore,
finalScores.Where(element => element == Scores.GREAT).Count(),
finalScores.Where(element => element == Scores.GOOD).Count(),
finalScores.Where(element => element == Scores.BAD).Count(),
totalScore > HighScoreData.Instance.GetHighScore(DancePerformanceObject.songId));
endScoreScreen.gameObject.SetActive(true);
HighScoreData.Instance.UpdateHighScore(DancePerformanceObject.songId, totalScore);
}

void Setup()
{
if (PersistentData.Instance != null)
{
DancePerformanceObject = PersistentData.Instance.performance;
}
avatarListSelf = new List<AvatarContainer>();
avatarListTeacher = new List<AvatarContainer>();
avatarListSelf.Add(new AvatarContainer(avatarContainerSelf));
avatarListTeacher.Add(new AvatarContainer(avatarContainerTeacher));

if (PersistentData.Instance.calibrated)
{
avatarContainerTeacher.transform.position = PersistentData.Instance.teacherPositions[0];
avatarContainerTeacher.transform.LookAt(PersistentData.Instance.playerPosition);
avatarContainerTeacher.transform.Rotate(new Vector3(-avatarContainerTeacher.transform.rotation.eulerAngles.x, 180, -avatarContainerTeacher.transform.rotation.eulerAngles.z));

videoCube.transform.position = PersistentData.Instance.kinectPosition + Vector3.up;
videoCube.transform.LookAt(PersistentData.Instance.playerPosition);
videoCube.transform.Rotate(new Vector3(-videoCube.transform.rotation.eulerAngles.x, 180, -videoCube.transform.rotation.eulerAngles.z));
}

audioSource = GetComponent<AudioSource>();
song = DancePerformanceObject.SongObject.SongClip;
audioSource.clip = song;
danceData = DancePerformanceObject.danceData.LoadDanceDataFromScriptableObject();

selfPoseInputGetter = getPoseGetter(selfPoseInputSource);

}

public void RestartSong()
{
endScoreScreen.gameObject.SetActive(false);

goals = new List<(float, DanceData)>();
for (int i = 0; i < DancePerformanceObject.goals.Count; i++)
{
goals.Add((DancePerformanceObject.goalStartTimestamps[i], DancePerformanceObject.goals[i]));
}
audioSource.time = 0;
currentId = 0;
finished = false;
audioSource.PlayDelayed(0.5f);
}

public void QuitToMenu()
{
SceneManager.LoadScene("StartMenu", LoadSceneMode.Single);
}
}
}
}
39 changes: 39 additions & 0 deletions unity/Assets/Scripts/Data/DanceData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public static DanceData LoadFromJSON(string fileName)
string jsonString = File.ReadAllText("jsondata/" + fileName);
return JsonUtility.FromJson<DanceData>(jsonString);
}


}

public enum DanceDifficulty
Expand Down Expand Up @@ -108,6 +110,43 @@ public PoseData toPoseData()
}
return poseData;
}

public static DancePose fromPoseData(PoseData poseData, float timeStamp = 0)
{
DancePose dancePose = new DancePose();

for(int i = 0; i < (int)JointId.Count; ++i)
{
dancePose.positions[i] = poseData.data[i].Position;
dancePose.orientations[i] = poseData.data[i].Orientation;
dancePose.timestamp = timeStamp;
}

return dancePose;
}

public static DancePose Body2DancePose(Body body, float ts)
{
DancePose dancePose = new DancePose();
dancePose.timestamp = ts;
for (int i = 0; i < (int)JointId.Count; ++i)
{
// write recorded poses to file
Microsoft.Azure.Kinect.BodyTracking.Joint joint = body.Skeleton.GetJoint(i);
var pos = joint.Position;
var orientation = joint.Quaternion;
// save raw data
var v = new Vector3(pos.X, pos.Y, pos.Z);
var r = new Quaternion(orientation.X, orientation.Y, orientation.Z, orientation.W);

dancePose.positions[i] = v;
dancePose.orientations[i] = r;
}

return dancePose;
}

}


}
69 changes: 69 additions & 0 deletions unity/Assets/Scripts/PoseGetting/FilePoseGetter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,34 @@
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;

namespace PoseTeacher
{
public class FilePoseGetter : PoseGetter
{

private bool recording;
public override bool Recording
{
get
{
return recording;
}
set
{
if (value)
{
RecordingStartTicks = DateTime.Now.Ticks;
}
else
{
LastTimeStamp = CurrentTimeStamp;
}
recording = value;
}
}

bool loop = false;

IEnumerator<string> SequenceEnum;
Expand Down Expand Up @@ -37,9 +60,41 @@ public override PoseData GetNextPose()
string frame_json = SequenceEnum.Current;
PoseData fake_live_data = PoseDataUtils.JSONstring2PoseData(frame_json);
CurrentPose = fake_live_data;

// also save as dance pose
CurrentTicks = System.DateTime.Now.Ticks;
CurrentDancePose = DancePose.fromPoseData(CurrentPose, GetTimeStamp());
if (Recording)
{
recordedDanceData.poses.Add(CurrentDancePose);
}

return CurrentPose;
}

public override DancePose GetNextDancePose()
{
if (!SequenceEnum.MoveNext())
{
// Quick and dirty way to loop (by reloading file)
if (SequenceEnum == null || loop)
{
LoadData();
SequenceEnum.MoveNext();
}
}

string frame_json = SequenceEnum.Current;
PoseData fake_live_data = PoseDataUtils.JSONstring2PoseData(frame_json);
CurrentTicks = System.DateTime.Now.Ticks;
CurrentDancePose = DancePose.fromPoseData(CurrentPose, GetTimeStamp());
if (Recording)
{
recordedDanceData.poses.Add(CurrentDancePose);
}
return CurrentDancePose;
}

public override void Dispose(){}

public void RestartFile()
Expand All @@ -51,6 +106,20 @@ void LoadData()
{
SequenceEnum = File.ReadLines(ReadDataPath).GetEnumerator();
}

public override void SaveDanceData()
{
string timestamp = DateTime.Now.ToString("yyyy_MM_dd-HH_mm_ss");
string recordingName = "Recordings/recording-" + timestamp;
DanceDataScriptableObject.SaveDanceDataToScriptableObject(recordedDanceData, recordingName, true);

// After Saving reset recorded data to have space for a new one
recordedDanceData = new DanceData();
}


}


}

Loading