Я изо всех сил пытаюсь с Kinect для Windows SDK создать приложение для проведения (с С#).
В основном мне нужно отслеживать одну руку (обычно правую) дирижера и распознавать его скорость в направлении (BPM), чтобы отправить это значение в другое приложение через MIDI.
Я начал с того, что SkeletonFramesReadyEvent
добавил JointType.HandRight
с отметкой времени DateTime.Now.Ticks
в историю List
, которая обновляется и удаляет первую запись. Храню историю 60 кадров (2 секунды).
Я рассчитываю BPM, ища последний минимум и максимум Joint.Position.Y
, а затем вычисляю разницу и делю bpm = 60*ticksPerSecond/diff
. Однако результат неверный. Есть ли другой способ сделать это? Что мне не хватает?
Это то, что я использую до сих пор:
public int DetectBPM(JointType type)
{
// we have not history yet
if (!HasHistory()) return 0;
// only calculate every second
var detectTime = DateTime.Now.Second;
if (_lastBPM != 0 && _lastBPMDectect == detectTime) return _lastBPM;
// search last high/low boundaries
var index = (int) type;
var list = History[index];
var i = list.Count - 1;
var lastHigh = list[i];
var lastLow = list[i];
// shift to last peak first
while (i > 0 && list[i].Joint.Position.Y >= list[i - 1].Joint.Position.Y) i--;
// find last low
while (i >= 0 && lastLow.Joint.Position.Y >= list[i].Joint.Position.Y) lastLow = list[i--];
// find last high
while (i >= 0 && lastHigh.Joint.Position.Y <= list[i].Joint.Position.Y) lastHigh = list[i--];
var ticks = lastLow.Timestamp - lastHigh.Timestamp;
var elapsedTime = new TimeSpan(ticks);
var bpm = (int) (60000/elapsedTime.TotalMilliseconds);
Console.WriteLine("DEBUG: BPM = " + _lastBPM + ", elapsedMS: " + elapsedTime.TotalMilliseconds);
_lastBPMDectect = detectTime;
_lastBPM = bpm;
return _lastBPM;
}