def _make_pitch_candidates( used_primes: typing.Tuple[int, ...] = (3, 5, 7, 11), max_exponent: int = 2, max_combinations: int = 2, ) -> typing.Tuple[pitches.JustIntonationPitch, ...]: elements_per_prime = [[] for _ in used_primes] for tonality in (True, False): for nth_prime, prime in enumerate(used_primes): nth_prime_number = primesieve.count_primes(prime) for exponent in range(1, max_exponent + 1): exponents = [0 for _ in range(nth_prime_number)] exponents[-1] = exponent if not tonality: exponents[-1] = -exponents[-1] pitch = pitches.JustIntonationPitch(exponents) elements_per_prime[nth_prime].append(pitch) candidates = [pitches.JustIntonationPitch()] for combination in itertools.product(*elements_per_prime): for n_pitches in range(1, max_combinations + 1): for elements_to_combine in itertools.combinations( combination, n_pitches): pitch = functools.reduce(operator.add, elements_to_combine) if pitch not in candidates: candidates.append(pitch) for candidate in candidates: candidate.normalize() return tuple(candidates)
def _make_harmonies_and_roots( k: int, r: typing.Sequence[int] ) -> typing.Tuple[typing.Dict[str, typing.Tuple[ pitches.JustIntonationPitch, ...]], typing.Dict[str, typing.Tuple[ pitches.JustIntonationPitch, ...]], ]: harmonies = {} roots = {} for exponent_k, exponent_r, name in ( (1, 1, zimmermann_constants.OTONAL_HARMONY_NAME), (-1, -1, zimmermann_constants.UTONAL_HARMONY_NAME), (-1, 1, zimmermann_constants.F_OTONAL_HARMONY_NAME), (1, -1, zimmermann_constants.F_UTONAL_HARMONY_NAME), ): harmony = [] k_pitch = pitches.JustIntonationPitch( fractions.Fraction(k**exponent_k).limit_denominator(k)) for prime_number in r: r_pitch = pitches.JustIntonationPitch( fractions.Fraction( prime_number**exponent_r).limit_denominator( prime_number)) harmony.append(r_pitch + k_pitch) harmonies.update({name: tuple(harmony)}) roots.update({name: k_pitch}) return harmonies, roots
def _post_process_brahms_melody(brahms_melody: basic.SequentialEvent): brahms_melody.tie_by(lambda event0, event1: event0.pitch_or_pitches == event1.pitch_or_pitches) if min( functools.reduce( operator.add, brahms_melody.get_parameter( "pitch_or_pitches"))) > pitches.JustIntonationPitch("1/1"): brahms_melody.set_parameter( "pitch_or_pitches", lambda pitch_or_pitches: [ pitch + pitches.JustIntonationPitch("1/2") for pitch in pitch_or_pitches ], )
def _extend_cps_scale_melody( given_melody: typing.Tuple[pitches.JustIntonationPitch, ...], given_scale: typing.Tuple[pitches.JustIntonationPitch, ...], size_of_resulting_melody: int, ) -> typing.Tuple[pitches.JustIntonationPitch, ...]: pitch_to_counter = {pitch.exponents: 0 for pitch in given_scale} for pitch in given_melody: pitch_to_counter[pitch.exponents] += 1 neighbours = _find_neighbours_for_each_pitch(given_scale) resulting_melody = list(map(copy.copy, given_melody)) while len(resulting_melody) < size_of_resulting_melody: for nth_pair, melody_pitches in enumerate( tuple(zip(resulting_melody, resulting_melody[1:]))): neighbours_pitches = tuple(neighbours[pitch.exponents] for pitch in melody_pitches) common_neighbours = tuple(neighbours_pitches[0].intersection( neighbours_pitches[1])) if not common_neighbours: raise NotImplementedError( f"Couldn't find any neighbour between '{melody_pitches[0]}' and" f" '{melody_pitches[1]}'!") choosen_neighbour = min( common_neighbours, key=lambda exponents: pitch_to_counter[exponents]) pitch_to_counter[choosen_neighbour] += 1 choosen_neighbour_as_pitch = pitches.JustIntonationPitch( choosen_neighbour) resulting_melody.insert((nth_pair * 2) + 1, choosen_neighbour_as_pitch) if len(resulting_melody) >= size_of_resulting_melody: break return tuple(resulting_melody)
def _load_transitional_harmonies( ) -> typing.Dict[typing.Tuple[typing.Tuple[int, ...], typing.Tuple[int, ...]], typing.Tuple[pitches.JustIntonationPitch, ...], ]: with open("ot2/analysis/data/transition_harmonies6.json", "r") as f: transitional_harmonies_raw = json.load(f) transitional_harmonies = {} for ( current_pitch, previous_pitch, next_pitch, solution, _, ) in transitional_harmonies_raw: solution_as_pitches = tuple( pitches.JustIntonationPitch(pitch) for pitch in solution) transitional_harmonies.update({ ( tuple(current_pitch), tuple(previous_pitch), tuple(next_pitch), ): solution_as_pitches }) return transitional_harmonies
def synthesize_applied_cantus_firmus(cantus_firmus: basic.SequentialEvent): from mutwo.converters.frontends import midi drone = basic.SequentialEvent([ music.NoteLike( note.pitch_or_pitches[0] - pitches.JustIntonationPitch("2/1"), note.duration, ) if note.pitch_or_pitches else note for note in cantus_firmus ]) melody = basic.SequentialEvent([]) for note in cantus_firmus: if note.pitch_or_pitches: pitches_cycle = itertools.cycle(sorted(note.pitch_or_pitches)) [ melody.append( music.NoteLike(next(pitches_cycle), fractions.Fraction(1, 6))) for _ in range(int(note.duration * 6)) ] else: melody.append(copy.copy(note)) for name, sequential_event in (("drone", drone), ("melody", melody)): converter = midi.MidiFileConverter( "builds/materials/applied_cantus_firmus_{}.mid".format(name)) converter.convert( sequential_event.set_parameter("duration", lambda duration: duration * 4, mutate=False))
def _select_from_potential_brahms_melodies( potential_brahms_melodies: typing.Tuple[basic.SequentialEvent, ...], current_bar: music.NoteLike, next_bar: music.NoteLike, ) -> basic.SequentialEvent[music.NoteLike]: pitches_per_bar0, pitches_per_bar1 = (set( map(lambda pitch: pitch.normalize(mutate=False).exponents, pitch_or_pitches)) for pitch_or_pitches in ( current_bar.pitch_or_pitches, next_bar.pitch_or_pitches, )) common_pitches = tuple( pitches.JustIntonationPitch(pitch) for pitch in pitches_per_bar0.intersection(pitches_per_bar1)) is_last_pitch_connection_pitch_per_brahms_melody = tuple( brahms_melody[-1].pitch_or_pitches[0].normalize( mutate=False) in common_pitches for brahms_melody in potential_brahms_melodies) if any(is_last_pitch_connection_pitch_per_brahms_melody): nth_melody_is_possible = is_last_pitch_connection_pitch_per_brahms_melody.index( True) return potential_brahms_melodies[nth_melody_is_possible] else: return basic.SequentialEvent( [music.NoteLike([], current_bar.duration)])
def _convert_western_pitch_to_ji_pitch( western_pitch: pitches.WesternPitch, ) -> pitches.JustIntonationPitch: difference_to_reference = western_pitch - concert_pitch.REFERENCE return pitches.JustIntonationPitch( pitches.JustIntonationPitch.cents_to_ratio( difference_to_reference * 100 ).limit_denominator(1000) )
def get_relationship_to_deepest_fundamental(self) -> int: if self.cycle_index == 0: return 1 else: ratio_to_lowest_cycle = len(GROUPS[self.cycle_index]) // len( GROUPS[0]) responsible_group = GROUPS[0][self.harmony_index // ratio_to_lowest_cycle] ratio_to_deepest_fundamental = pitches.JustIntonationPitch( (self.fundamental - responsible_group.fundamental).exponents).ratio return ratio_to_deepest_fundamental
def _find_neighbours_for_each_pitch( scale: typing.Tuple[pitches.JustIntonationPitch, ...] ) -> typing.Dict[typing.Tuple[int, ...], typing.Tuple[typing.Set[int], ...]]: pitch_to_pitch_neighbours = {pitch.exponents: set([]) for pitch in scale} for pitch0, pitch1 in itertools.combinations(scale, 2): intersection = pitch0.intersection(pitch1, mutate=False) intersection.normalize() if intersection != pitches.JustIntonationPitch("1/1"): pitch_to_pitch_neighbours[pitch0.exponents].add(pitch1.exponents) pitch_to_pitch_neighbours[pitch1.exponents].add(pitch0.exponents) return pitch_to_pitch_neighbours
def imitate( melodic_pitches: typing.Tuple[abc.Pitch, ...], harmony: typing.Tuple[pitches.JustIntonationPitch, ...], cent_factor: int = 10, ) -> typing.Tuple[pitches.JustIntonationPitch, ...]: """Find best imitation of melodic pitches with given harmony. :param melodic_pitches: The pitches which contour shall be imitated. :param harmony: The given harmony. :param cent_factor: Factor to multiply cent values. Higher values give more precise results. This function uses Googles ortools for constraint programming. """ distance_in_cents_between_melodic_pitches = tuple( int( abc.Pitch.hertz_to_cents(pitch0.frequency, pitch1.frequency) * cent_factor) for pitch0, pitch1 in zip(melodic_pitches, melodic_pitches[1:])) harmony_with_one_octave_lower = tuple( pitch + pitches.JustIntonationPitch("1/2") for pitch in harmony) harmony_with_one_octave_higher = tuple( pitch + pitches.JustIntonationPitch("2/1") for pitch in harmony) available_pitches = (harmony_with_one_octave_lower + harmony + harmony_with_one_octave_higher) cents_to_pitch = { int(pitch.cents * cent_factor): pitch for pitch in available_pitches } model, variables = _build_model(distance_in_cents_between_melodic_pitches, cents_to_pitch, melodic_pitches) solver = cp_model.CpSolver() solver.Solve(model) return tuple(cents_to_pitch[solver.Value(variable)] for variable in variables)
def _make_families( family_data_per_part: typing.Tuple[typing.Tuple[typing.Tuple[int, ...], float], ...], composition_structure: structure.StructureType, ) -> basic.SequentialEvent[typing.Union[basic.SimpleEvent, families.FamilyOfPitchCurves]]: import progressbar families_for_all_parts = basic.SequentialEvent([]) with progressbar.ProgressBar(max_value=len(family_data_per_part)) as bar: nth_part = 0 for part0, part1, family_data in zip( basic.SequentialEvent([None]) + composition_structure, composition_structure, family_data_per_part, ): duration_in_seconds = part1[0].duration duration_of_following_cengkok_part_in_seconds = part1[ 1].duration_in_seconds if part0: last_pitch_of_last_melodic_phrase = part0[1][-1].root else: last_pitch_of_last_melodic_phrase = pitches.JustIntonationPitch( "1/1") first_pitch_of_next_melodic_phrase = part1[1][0].root n_root_notes_per_family, density, *rest_distribution = family_data if rest_distribution: rest_distribution = rest_distribution[0] family_structure_for_current_part = _family_data_to_families( last_pitch_of_last_melodic_phrase, first_pitch_of_next_melodic_phrase, duration_in_seconds, duration_of_following_cengkok_part_in_seconds, n_root_notes_per_family, density, rest_distribution, ) assert round(family_structure_for_current_part.duration, 5) == round( duration_in_seconds + duration_of_following_cengkok_part_in_seconds, 5) families_for_all_parts.extend(family_structure_for_current_part) bar.update(nth_part) nth_part += 1 return families_for_all_parts
def _find_connection_pitch_between_two_pitches( scale: typing.Tuple[pitches.JustIntonationPitch, ...] ) -> typing.Dict[typing.Tuple[typing.Tuple[int, ...], ...], pitches.JustIntonationPitch]: pitch_pair_to_connection_pitch = {} for pitch0, pitch1 in itertools.combinations(scale, 2): intersection = pitch0.intersection(pitch1, mutate=False, strict=True) intersection.normalize() if intersection == pitches.JustIntonationPitch("1/1"): intersection = pitch0.intersection(pitch1, mutate=False, strict=False) intersection.normalize() if intersection != pitches.JustIntonationPitch("1/1"): pitch_pair_to_connection_pitch.update({ (pitch0.exponents, pitch1.exponents): intersection }) pitch_pair_to_connection_pitch.update({ (pitch1.exponents, pitch0.exponents): intersection }) return pitch_pair_to_connection_pitch
def load_cantus_firmus(): import music21 m21_lasso_measures = music21.converter.parse( # "ot2/analysis/data/lasso_cantus_firmus.mxl" "ot2/analysis/data/lasso_adjusted_cantus_firmus.mxl" )[1].getElementsByClass("Measure") mutwo_lasso = basic.SequentialEvent([]) current_root_pitch = None previous_event = None melodic_pitch_counter = 0 for measure in m21_lasso_measures: for event in measure: if isinstance(event, music21.note.GeneralNote): event_duration = fractions.Fraction(event.duration.quarterLength) / 4 if previous_event and previous_event.isRest and not event.isRest: current_root_pitch = cantus_firmus_constants.START_PITCH_TO_ROOT[ event.pitch.name.lower() ] if event.isRest: melodic_pitch_counter = 0 mutwo_lasso.append(music.NoteLike([], event_duration)) else: try: ji_ratios = cantus_firmus_constants.INTERVALS[ melodic_pitch_counter ] except IndexError: ji_ratios = cantus_firmus_constants.INTERVALS[-1] duration_per_ratio = event_duration / len(ji_ratios) for ji_ratio in ji_ratios: pitch = ( ji_ratio + current_root_pitch - pitches.JustIntonationPitch("2/1") ) note = music.NoteLike([pitch], duration_per_ratio) mutwo_lasso.append(note) melodic_pitch_counter += 1 previous_event = event return mutwo_lasso
def make_applied_cantus_firmus( cantus_firmus: basic.SequentialEvent, ) -> basic.SequentialEvent[music.NoteLike]: transitional_harmonies = _load_transitional_harmonies() cantus_firmus = _process_cantus_firmus(cantus_firmus) previous_pitch_or_pitches = None applied_cantus_firmus = basic.SequentialEvent([]) roots = (cantus_firmus_constants.START_PITCH_TO_ROOT[start_pitch] for start_pitch in "c e a c e a d g c e a".split(" ")) current_root = None for pitch_or_pitches, next_pitch_or_pitches, duration in zip( cantus_firmus.get_parameter("pitch_or_pitches"), cantus_firmus.get_parameter("pitch_or_pitches")[1:] + (None, ), cantus_firmus.get_parameter("duration"), ): if pitch_or_pitches: if current_root is None: current_root = next(roots) current_pitch = pitch_or_pitches[0] previous_pitch = (previous_pitch_or_pitches[0] if previous_pitch_or_pitches else current_pitch) next_pitch = (next_pitch_or_pitches[0] if next_pitch_or_pitches else current_pitch) harmony = [ current_pitch + pitch for pitch in transitional_harmonies[tuple( (pitch - current_root).normalize(mutate=False).exponents for pitch in (current_pitch, previous_pitch, next_pitch))] ] # MAKE EVERYTHING MORE READABLE (go down to pitch 'e') harmony = [ pitch - pitches.JustIntonationPitch('3/2') for pitch in harmony ] event = music.NoteLike(harmony, duration) else: event = music.NoteLike([], duration) current_root = None applied_cantus_firmus.append(event) previous_pitch_or_pitches = pitch_or_pitches return applied_cantus_firmus
def _make_connections( k: int, r: typing.Sequence[int] ) -> typing.Dict[typing.Tuple[str, str], typing.Tuple[ pitches.JustIntonationPitch, ...]]: connections = {} connection_pitches_0 = (pitches.JustIntonationPitch( "{}/1".format(k)), ) connection_pitches_1 = (pitches.JustIntonationPitch( "1/{}".format(k)), ) connection_pitches_2 = tuple( pitches.JustIntonationPitch("{}/1".format(prime)) for prime in r) connection_pitches_3 = tuple( pitches.JustIntonationPitch("1/{}".format(prime)) for prime in r) for harmony0, harmony1, connection_pitches in ( ( zimmermann_constants.OTONAL_HARMONY_NAME, zimmermann_constants.F_UTONAL_HARMONY_NAME, connection_pitches_0, ), ( zimmermann_constants.UTONAL_HARMONY_NAME, zimmermann_constants.F_OTONAL_HARMONY_NAME, connection_pitches_1, ), ( zimmermann_constants.OTONAL_HARMONY_NAME, zimmermann_constants.F_OTONAL_HARMONY_NAME, connection_pitches_2, ), ( zimmermann_constants.UTONAL_HARMONY_NAME, zimmermann_constants.F_UTONAL_HARMONY_NAME, connection_pitches_3, ), ): connections.update({ (harmony0, harmony1): connection_pitches + (pitches.JustIntonationPitch("1/1"), ) }) connections.update({ (harmony1, harmony0): connection_pitches + (pitches.JustIntonationPitch("1/1"), ) }) return connections
from mutwo.parameters import pitches scale_to_tune = tuple( pitches.JustIntonationPitch(pitch) for pitch in "1/1 9/8 8/7 5/4 4/3 11/8 16/11 3/2 8/5 7/4 16/9".split(" ")) roots = tuple( pitches.JustIntonationPitch(pitch) for pitch in "3/2 4/3 5/4 8/5 7/4 8/7 11/8 16/11".split(" ")) transpose = pitches.JustIntonationPitch("3/4") for root in roots: name = "{}_{}.scl".format(root.primes[-1], root.tonality) with open("scl/{}".format(name), "w") as f: f.write("! {}\n".format(name)) f.write("!\n") f.write("JustIntonationScale_{}\n".format(name)) f.write("12\n") f.write("!\n") for pitch in scale_to_tune: new_pitch = pitch + transpose + root f.write("{}/{}\n".format(new_pitch.numerator, new_pitch.denominator)) f.write("2/1\n")
def apply_octave_mark(pitch, octave_mark): octave_mark = int(octave_mark) oct_pitch = pitches.JustIntonationPitch([octave_mark]) return pitch + oct_pitch
adjusted_harmony, weight_per_given_pitch, WEIGHT_FOR_INTER_PITCHES, n_pitches - len(harmony), pitch_candidates, harmonicity_map, ) return tuple(sorted(adjusted_harmony + added_pitches)), harmonicity if __name__ == "__main__": import json available_pitches = tuple( pitches.JustIntonationPitch(pitch) for pitch in "3/2 5/4 7/4 11/8 4/3 8/5 8/7 16/11".split(" ")) data = [] for current_pitch, next_pitch, previous_pitch in itertools.product( available_pitches, available_pitches, available_pitches): solution = find_transitional_harmony( 5, current_pitch, previous_pitch, next_pitch, ) data.append(( current_pitch.exponents, previous_pitch.exponents,
abjad_score = abjad.Score([abjad.Staff([abjad_voice])]) lilypond_file = abjad.LilyPondFile( items=[abjad_score], includes=["ekme-heji-ref-c.ily"]) abjad.persist.as_pdf( lilypond_file, "{}/{}.pdf".format(harmony_path, pitch_variant_name), ) try: os.mkdir(DRONE_BUILD_PATH) except FileExistsError: pass DRONE_AMBITUS = ambitus.Ambitus(pitches.JustIntonationPitch("1/4"), pitches.JustIntonationPitch("1/2")) for structural_prime in (3, 5, 7, 9, 11, 13): for tonality in (True, False): if tonality: pitch = pitches.JustIntonationPitch( "{}/1".format(structural_prime)) else: pitch = pitches.JustIntonationPitch( "1/{}".format(structural_prime)) for nth_pitch_variant, pitch_variant in enumerate( DRONE_AMBITUS.find_all_pitch_variants(pitch)): sequential_event = basic.SequentialEvent( [music.NoteLike(pitch_variant, 16, 0.2)])
# (3) register pitches in each cycle # #################################### HARMONIES_IN_CORRECT_REGISTER = [[], [], []] def make_registered_pitch_group_from_fundamental_and_pitch_group( fundamental: pitches.JustIntonationPitch, pitch_group: tuple) -> tuple: intervals = (pitch - pitch_group[0] for pitch in pitch_group) registered_pitch_group = tuple(fundamental + interval for interval in intervals) return registered_pitch_group # lowest cycle for pitch_group_in_lowest_cycle in pitch_groups_per_cycle[0]: fundamental = pitches.JustIntonationPitch( pitch_group_in_lowest_cycle[0].normalize(mutate=False).exponents) registered_pitch_group_in_lowest_cycle = make_registered_pitch_group_from_fundamental_and_pitch_group( fundamental, pitch_group_in_lowest_cycle) HARMONIES_IN_CORRECT_REGISTER[0].append( registered_pitch_group_in_lowest_cycle) # central & highest cycle for nth_pitch_groups, pitch_groups in enumerate(pitch_groups_per_cycle[1:]): lower_pitch_group_index_divider = len(pitch_groups) // len( pitch_groups_per_cycle[nth_pitch_groups]) for nth_pitch_group, pitch_group_in_central_cycle in enumerate( pitch_groups): simultaneous_lower_pitch_group_index = ( nth_pitch_group // lower_pitch_group_index_divider) simultaneous_lower_pitch_group = HARMONIES_IN_CORRECT_REGISTER[ nth_pitch_groups][simultaneous_lower_pitch_group_index]
print("") candidates = [] for possible_diatonic_pitch in "c d e f g a b".split(" "): fitness = sum( len( pitch.get_closest_pythagorean_pitch_name( possible_diatonic_pitch)) for pitch in best[1]) candidates.append((possible_diatonic_pitch, fitness)) best = min(candidates, key=operator.itemgetter(1))[0] print(best) INTERVALS = ( (pitches.JustIntonationPitch("7/4"), ), (pitches.JustIntonationPitch("8/5"), ), (pitches.JustIntonationPitch("3/2"), pitches.JustIntonationPitch("16/11")), (pitches.JustIntonationPitch("5/4"), ), (pitches.JustIntonationPitch("16/11"), ), (pitches.JustIntonationPitch("4/3"), ), (pitches.JustIntonationPitch("7/4"), ), (pitches.JustIntonationPitch("7/4"), ), (pitches.JustIntonationPitch("16/11"), ), (pitches.JustIntonationPitch("4/3"), ), (pitches.JustIntonationPitch("5/4"), ), ( pitches.JustIntonationPitch("16/11"), pitches.JustIntonationPitch("3/2"), ), (pitches.JustIntonationPitch("8/5"), ),
from mutwo.converters.frontends import abjad as mutwo_abjad from mutwo.events import basic from mutwo.events import music from mutwo.parameters import pitches with open("solutions.json", "r") as f: DATA = json.load(f) converter = mutwo_abjad.SequentialEventToAbjadVoiceConverter( mutwo_pitch_to_abjad_pitch_converter=mutwo_abjad.MutwoPitchToHEJIAbjadPitchConverter() ) lilypond_file = abjad.LilyPondFile(includes=["ekme-heji-ref-c.ily"]) for current_pitch, previous_pitch, next_pitch, solution, harmonicity in DATA: movement_pitches = tuple( pitches.JustIntonationPitch(exponents) for exponents in (previous_pitch, current_pitch, next_pitch) ) solution_pitches = tuple( pitches.JustIntonationPitch(exponents) for exponents in solution ) sequential_event = basic.SequentialEvent([]) for movement_pitch in movement_pitches: sequential_event.append( music.NoteLike(movement_pitch, fractions.Fraction(1, 3)) ) for solution_pitch in solution_pitches: sequential_event.append( music.NoteLike(solution_pitch, fractions.Fraction(1, 5))
def register_pitches1(pitch_or_pitches): return [ pitch + pitches.JustIntonationPitch("2/1") for pitch in pitch_or_pitches ]
AMBITUS_SUSTAINING_INSTRUMENTS_WESTERN_PITCHES = ambitus.Ambitus( pitches.WesternPitch("af", 3), pitches.WesternPitch("e", 5), ) AMBITUS_SUSTAINING_INSTRUMENTS_JUST_INTONATION_PITCHES = ambitus.Ambitus( _convert_western_pitch_to_ji_pitch( AMBITUS_SUSTAINING_INSTRUMENTS_WESTERN_PITCHES.borders[0] ), _convert_western_pitch_to_ji_pitch( AMBITUS_SUSTAINING_INSTRUMENTS_WESTERN_PITCHES.borders[1] ), ) AMBITUS_DRONE_INSTRUMENT = ambitus.Ambitus( pitches.JustIntonationPitch("1/4"), pitches.JustIntonationPitch("1/2") ) AMBITUS_KEYBOARD = ambitus.Ambitus( pitches.JustIntonationPitch("1/4"), pitches.JustIntonationPitch("4/1") ) # how many voices (staves) one instrument owns INSTRUMENT_TO_N_VOICES = { ID_PERCUSSIVE: 1, ID_DRONE: 1, ID_NOISE: 1, ID_SUS0: 1, ID_SUS1: 1, ID_SUS2: 1, ID_KEYBOARD: 2,