"""
Not all output rates are going to be supported by the system sound card.
Choosing from a limited subset of preferred output rates is how we guarantee
that the system will be able to play the output audio.
Sample rates stolen from:
    https://en.wikipedia.org/wiki/Sampling_(signal_processing)
"""
supported_ouput_rates = [
    8000,   # Telephone, P25 audio (sufficient for speech, some consonants unintelligble)
    16000,  # Modern telephone/VoIP, good quality speech
    32000,  # FM radio
    44100,  # CD audio quality
    48000,
    50000,  # Uncommon but supported
    88200,
    96000,  # DVD/Blu-ray audio
    192000, # Too much.
]

def score(pair, target_output=32000, target_ratio=10):
    """
    Heuristic for scoring input & output sample rates. The criteria are:
     - closest to 44.1 kHz is better;
     - closer to a ratio of 10 is better,
     - additionally penalising ratios lower than 10.

    Lower scores are better.

    This should result in selected sample rates that give good audio quality
    without wasting CPU cycles on a needlessly high input rate.
    """

    # Give the worst score possible for impossible pairs.
    if pair[0] % pair[1] != 0:
        return float("inf")

    ratio = pair[0] // pair[1]

    return abs(pair[1] - target_output)/2500 \
        + max(0, target_output - pair[1])/2500 \
        + abs(ratio - target_ratio)**0.8 \
        + max(0, target_ratio - ratio)**2

def flatten(l):
    return [item for sublist in l for item in sublist]

def flatten_dict(d):
    return [(key,value) for key,rates in d.items() for value in rates]

def get_pairs(input_rate):
    return [
        (input_rate, rate)
        for rate in supported_ouput_rates
        if (input_rate % rate == 0)
    ]

def supported_sample_rates(supported_input_rates):
    return {
        in_rate: [out_rate for out_rate in supported_ouput_rates if in_rate % out_rate == 0]
        for in_rate in supported_input_rates
    }

def preferred_sample_rates(supported_input_rates):
    return sorted(flatten_dict(supported_sample_rates(supported_input_rates)), key=score)
