public void DidOutputMetadataObjects(AVCaptureMetadataOutput captureOutput, AVMetadataObject[] metadataObjects, AVCaptureConnection connection)
        {
            if (codeFrame is null || preview is null)
            {
                return;
            }

            if (metadataObjects.Length == 0)
            {
                codeFrame.Frame = CGRect.Empty;
                return;
            }

            var readableObject = metadataObjects[0] as AVMetadataMachineReadableCodeObject;

            if (readableObject.Type != AVMetadataObjectType.QRCode)
            {
                return;
            }

            var qrObject = preview.GetTransformedMetadataObject(readableObject);

            codeFrame.Frame = qrObject.Bounds;

            if (readableObject.StringValue is string value)
            {
                Detected?.Invoke(this, new BarcodeDetectedEventArgs(value));
            }
        }
        void step(NSTimer timer)
        {
            if (sessionManager.Barcodes == null || sessionManager.Barcodes.Count < 1)
            {
                return;
            }

            lock (sessionManager) {
                barcodeIndex = (barcodeIndex + 1) % sessionManager.Barcodes.Count;
                var barcode = (AVMetadataMachineReadableCodeObject)sessionManager.Barcodes [barcodeIndex];

                if (barcodeTimer != null)
                {
                    barcodeTimer.Invalidate();
                }
                barcodeTimer = NSTimer.CreateScheduledTimer(0.5, this, new Selector("removeDetectedBarcodeUI"), null, false);
                var transformedBarcode =
                    (AVMetadataMachineReadableCodeObject)previewLayer.GetTransformedMetadataObject(barcode);
                CGPath barcodeBoundary = createPathForPoints(transformedBarcode.Corners);

                CATransaction.Begin();
                CATransaction.DisableActions = true;
                removeDetectedBarcodeUI();
                barcodeTargetLayer.AddSublayer(barcodeOverlayLayer(barcodeBoundary, OverlayColor));
                CATransaction.Commit();

                string noteString = barcode.StringValue;
                int    note       = 0;
                if (int.TryParse(noteString, out note))
                {
                    // barcode data is a MIDI note (or at least an int that we presume can be a note
                    note -= 24;
                    if (note >= 0 && note <= 127)
                    {
                        synth.StartPlayNoteNumber(note);
                        Thread.Sleep(TimeSpan.FromMilliseconds(0.5));
                        synth.StopPlayNoteNumber(note);
                    }
                }
                else
                {
                    // barcode data is something else
                    Console.WriteLine("Barcode string data: " + noteString);
                }
            }
        }