protected virtual void SkeletonDataChange(SkeletonDataChangeEventArgs e)
 {
     if (SkeletonDataChanged != null)
     {
         SkeletonDataChanged(this, e);
     }
 }
        // Event Handler for SkeletonFrameReady events
        // (A new frame of SkeletonStream data is available)
        private void KinectSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            // Initialize/empty the skeletonStreamData array
            this.skeletonStreamData = new Skeleton[0];

            // Get the current SkeletonFrame and copy out the data
            using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
            {
                if (skeletonFrame != null)
                {
                    try
                    {
                        // Get the Skeleton data from the SkeletonFrame
                        skeletonStreamData = new Skeleton[skeletonFrame.SkeletonArrayLength];
                        skeletonFrame.CopySkeletonDataTo(skeletonStreamData);
                        // Dispatch the SkeletonDataChange event
                        SkeletonDataChangeEventArgs s = new SkeletonDataChangeEventArgs(skeletonStreamData);
                        SkeletonDataChange(s);
                    }
                    catch (NullReferenceException ex)
                    {
                        Console.WriteLine(ex.TargetSite + " - " + ex.Message);
                    }
                }
            }

            // Create the Skeleton image output
            using (DrawingContext dc = this.drawingGroup.Open())
            {
                // Draw a black background the size of our render
                dc.DrawRectangle(backgroundBrush, null, new Rect(0, 0, RenderWidth, RenderHeight));

                //Draw each Skeleton
                if (skeletonStreamData.Length != 0)
                {
                    foreach (Skeleton skeleton in skeletonStreamData)
                    {
                        // TO-DO: Render clipped edges

                        if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
                        {
                            DrawSkeletonBonesAndJoints(dc, skeleton.Joints);
                        }
                        else if (skeleton.TrackingState == SkeletonTrackingState.PositionOnly)
                        {
                            DrawSkeletonPosition(dc, skeleton.Position);
                        }
                    }
                }

                // Prevent any drawing outside the render area
                this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0, 0, RenderWidth, RenderHeight));
            }
        }
        // Event handler for KinectHelper.SkeletonDataChanged event
        // Used to get the positions of the user's hands and control the theremin
        private void SkeletonDataChange(object o, SkeletonDataChangeEventArgs e)
        {
            // Get the primary skeleton (the first one being tracked)
            Skeleton skel = null;
            for (int i = 0; i < e.skeletons.Length; i++)
            {
                if (e.skeletons[i].TrackingState == SkeletonTrackingState.Tracked)
                {
                    skel = e.skeletons[i];
                    break;
                }
            }
            // If no skeletons found, no need to continue
            if (skel == null)
                return;

            // Get the left and right hand positions from the skeleton
            Point freqHandPos = _helper.SkeletonPointToScreen(skel.Joints[_freqHand].Position);
            Point ampHandPos = _helper.SkeletonPointToScreen(skel.Joints[_ampHand].Position);

            // Determine the frequency based on the position of the right hand
            double freqValue = 1 - freqHandPos.Y / skeletonImage.Height;
            float customFreq;
            // If guides are enabled, determine the exact chromatic note to play
            if (_enableGuides)
                customFreq = GetChromaticNoteFrequency(freqValue);
            // If not, determine the frequency based on the exact position
            else
                customFreq = LinearToLog(freqValue);

            // Determine the amplitude based on the position of the left hand
            double ampValue = 1 - ampHandPos.Y / skeletonImage.Height;
            float customAmp = (float) ampValue;

            // Update the wave
            if (_player.IsPlaying())
            {
                _player.Frequency = customFreq;
                freqLabel.Content = customFreq;
                _player.Amplitude = customAmp;
                ampLabel.Content = customAmp;
            }
        }