# Path: bibliopixel/control/midi.py
#     MESSAGE_TYPES = set(s['type'] for s in mido.messages.specs.SPECS)
#     MESSAGE_TYPES = set()
# MIDO_ERROR = """You need to install mido.  Try
#     pip install mido
# """
# MIDO_BACKEND_ERROR = """You have the wrong rtmidi installed.  Try
#     pip uninstall -y rtmidi
#     pip install -y python-rtmidi
# """
#     EXTRACTOR = {
#         # There are more mido message types that we haven't used yet.
#         'keys_by_type': {
#             'aftertouch': (
#                 'port', 'channel', 'type', 'value'),
#             'control_change': (
#                 'port', 'channel', 'type', 'control', 'value'),
#             'note_off': (
#                 'port', 'channel', 'type', 'note', 'velocity'),
#             'note_on': (
#                 'port', 'channel', 'type', 'note', 'velocity'),
#             'pitchwheel': (
#                 'port', 'channel', 'type', 'pitch'),
#             'program_change': (
#                 'port', 'channel', 'type', 'program'),
#         },
# 
#         # Some numeric fields (channel, control, program and note) don't get
#         # normalized because they are basically names.
#         'normalizers': {
#             'pitch': lambda x: fractions.Fraction(x - 8192) / 8192,
#             'value': lambda x: fractions.Fraction(x) / 127,
#             'velocity': lambda x: fractions.Fraction(x) / 127,
#         },
# 
#         'omit': ('port', 'channel'),
#     }
# class Midi(control.ExtractedLoop):
#     def __init__(self, use_note_off=True, **kwds):
#     def messages(self):


import fractions, time, unittest
from bibliopixel.control import midi
from argparse import Namespace
from test.bibliopixel import patch
        'control_change': {
            '1': '.cc1',
            '2': '.cc2',
        },
        'pitchwheel': '.pitch',
    }

    def run_test(self, msgs, expected, routing=None, **kwds):
        with patch.patch(midi, 'mido', FakeMido(msgs)):
            class Root:
                pass

            root = Root()
            m = midi.Midi(routing=routing or self.routing, **kwds)
            m.set_project(root)
            with m.run_until_stop():
                time.sleep(0.1)

            self.assertEqual(vars(root), expected)

    def test_one(self):
        expected = {'note_on': (32, fractions.Fraction(96, 127))}
        self.run_test([C3], expected)

    def test_accept(self):
        expected = {
            'cc1': 1,
            'cc2': 1,
            'note_off': (32, 0),
            'note_on': (32, fractions.Fraction(96, 127)),

# Path: bibliopixel/control/midi.py
#     MESSAGE_TYPES = set(s['type'] for s in mido.messages.specs.SPECS)
#     MESSAGE_TYPES = set()
# MIDO_ERROR = """You need to install mido.  Try
#     pip install mido
# """
# MIDO_BACKEND_ERROR = """You have the wrong rtmidi installed.  Try
#     pip uninstall -y rtmidi
#     pip install -y python-rtmidi
# """
#     EXTRACTOR = {
#         # There are more mido message types that we haven't used yet.
#         'keys_by_type': {
#             'aftertouch': (
#                 'port', 'channel', 'type', 'value'),
#             'control_change': (
#                 'port', 'channel', 'type', 'control', 'value'),
#             'note_off': (
#                 'port', 'channel', 'type', 'note', 'velocity'),
#             'note_on': (
#                 'port', 'channel', 'type', 'note', 'velocity'),
#             'pitchwheel': (
#                 'port', 'channel', 'type', 'pitch'),
#             'program_change': (
#                 'port', 'channel', 'type', 'program'),
#         },
# 
#         # Some numeric fields (channel, control, program and note) don't get
#         # normalized because they are basically names.
#         'normalizers': {
#             'pitch': lambda x: fractions.Fraction(x - 8192) / 8192,
#             'value': lambda x: fractions.Fraction(x) / 127,
#             'velocity': lambda x: fractions.Fraction(x) / 127,
#         },
# 
#         'omit': ('port', 'channel'),
#     }
# class Midi(control.ExtractedLoop):
#     def __init__(self, use_note_off=True, **kwds):
#     def messages(self):


# Path: test/bibliopixel/control/midi_test.py
import fractions, time, unittest
from bibliopixel.control import midi
from argparse import Namespace
from test.bibliopixel import patch

        'control_change': {
            '1': '.cc1',
            '2': '.cc2',
        },
        'pitchwheel': '.pitch',
    }

    def run_test(self, msgs, expected, routing=None, **kwds):
        with patch.patch(midi, 'mido', FakeMido(msgs)):
            class Root:
                pass

            root = Root()
            m = midi.Midi(routing=routing or self.routing, **kwds)
            m.set_project(root)
            with m.run_until_stop():
                time.sleep(0.1)

            self.assertEqual(vars(root), expected)

    def test_one(self):
        expected = {'note_on': (32, fractions.Fraction(96, 127))}
        self.run_test([C3], expected)

    def test_accept(self):
        expected = {
            'cc1': 1,
            'cc2': 1,
            'note_off': (32, 0),
            'note_on': (32, fractions.Fraction(96, 127)),

            'pitch': fractions.Fraction(-7, 8),