concertina

No description provided
git clone https://git.woozle.org/neale/concertina.git

concertina / src
Neale Pickett  ·  2026-02-10

mklayouts.py

  1#! /usr/bin/python3
  2
  3import re
  4import sys
  5
  6baseMidiNote = {
  7    'C': 60,
  8    'D': 62,
  9    'E': 64,
 10    'F': 65,
 11    'G': 67,
 12    'A': 69,
 13    'B': 71,
 14}
 15
 16def abc2midi(s):
 17    if s in ('', '-'):
 18        return -1
 19    note = baseMidiNote[s[0].upper()]
 20    if s[0] in 'cdefgab':
 21        note += 12
 22    for m in s[1:]:
 23        if m == '^':
 24            note += 1
 25        elif m == '_':
 26            note -= 1
 27        elif m == ',':
 28            note -= 12
 29        elif m == "'":
 30            note += 12
 31    return note
 32
 33assert abc2midi('C') == 60
 34assert abc2midi('c') == 72
 35assert abc2midi("c^'") == 85
 36
 37
 38class Layout:
 39    def __init__(self, name):
 40        self.name = name
 41        self.notes = [[], []]
 42
 43    def add_row(self, buttons):
 44        assert len(buttons) == 10
 45        self.notes[0].append(buttons[:5])
 46        self.notes[1].append(buttons[5:])
 47
 48    def write(self, fd):
 49        assert len(self.notes) == 2
 50        fd.write('  { "%s",\n' % self.name)
 51        fd.write('    { // sides\n');
 52        for side in self.notes:
 53            assert len(side) == 4
 54            fd.write('      { // rows\n')
 55            for row in side:
 56                assert len(row) == 5
 57                fd.write('        { // buttons\n')
 58                for button in row:
 59                    fd.write('          {%d, %d}, // %s\n' % button)
 60                fd.write('        },\n')
 61            fd.write('      },\n')
 62        fd.write('    }\n')
 63        fd.write('  },\n')
 64
 65with sys.stdout as f:
 66    f.write('''/* Generated from layouts.txt by mklayouts.py */
 67#pragma once
 68
 69struct layout_t {
 70  char const *name;
 71  int8_t notes[2][4][5][2]; /* side, row, col, push/draw */
 72};
 73
 74const layout_t layouts[] = {
 75''')
 76    layout = None
 77    for line in open(sys.argv[1]):
 78        line = line.strip()
 79        parts = line.split()
 80        if line == '':
 81            continue
 82        if len(parts) < 11:
 83            if layout:
 84                layout.write(f)
 85            layout = Layout(line)
 86            continue
 87        if len(parts) != 11:
 88            raise RuntimeError("Wrong number of buttons")
 89        if parts[5] != '|':
 90            raise RuntimeError("Expecting separator, got %s" % parts[5])
 91        buttons = []
 92        for part in parts:
 93            if part == '|':
 94                continue
 95            button = part.replace('', '^').replace('', '_')
 96            names = button.split('/')
 97            if len(names) == 1:
 98                names.append(names[0])
 99            notes = [abc2midi(n) for n in names]
100            buttons.append((notes[0], notes[1], button))
101        layout.add_row(buttons)
102
103    if layout:
104        layout.write(f)
105    f.write("};\n")
106
107            
108