login

<     >

2020-09-14 20:25:03 (UTC-03:00)

Marcel Rodrigues <marcelgmr@gmail.com>

basic matrix plain-text load/save

diff --git a/seqt.c b/seqt.c
new file mode 100644
index 0000000..0d4501d
--- /dev/null
+++ b/seqt.c
@@ -0,0 +1,199 @@
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#define MAXTRACK    0x0010
+#define MAXVOICE    0x0008
+#define MAXINDEX    0x1000
+
+#define RECSIZE     0x20
+#define MAPSIZE     0x20
+
+#define MAXINPUTLINE    0x400
+
+#define REST    0
+#define CONT    1
+#define END     2
+
+int ntracks;
+char map[MAPSIZE][RECSIZE];
+unsigned char matrix[MAXTRACK][MAXINDEX][MAXVOICE];
+
+/* search key in map
+ * if key is found, return record index, otherwise return negative int:
+ *   return the index of the first empty record, negated
+ *   if map is full, return -MAPSIZE */
+int
+map_find(const char *key)
+{
+    int i;
+    for (i = 0; i < MAPSIZE; i++) {
+        if (!*map[i])
+            return -i;
+        if (!strcmp(map[i], key))
+            return i;
+    }
+    return -i;
+}
+
+/* put a key-value pair on the map
+ * if the key is already on the map, update its value
+ * return 0 on success, negative value on error:
+ *   -1: key-value pair is too large to fit on a record
+ *   -2: no record available on the map */
+int
+map_put(const char *key, const char *val)
+{
+    int keylen = strlen(key);
+    int vallen = strlen(val);
+    int i;
+    if (keylen + vallen + 2 > RECSIZE)
+        return -1;
+    i = map_find(key);
+    if (i == -MAPSIZE)
+        return -2;
+    if (i < 0) {
+        i = -i;
+        strcpy(&map[i][0], key);
+    }
+    strcpy(&map[i][keylen+1], val);
+    return 0;
+}
+
+/* get the value associated with the given key on the map
+ * returns a pointer to the value found or NULL if not found */
+char *
+map_get(const char *key)
+{
+    int i = map_find(key);
+    if (i < 0)
+        return NULL;
+    return &map[i][strlen(key)+1];
+}
+
+typedef enum TxtStt {NTRK, MTDT, TKNM, EVNT} TxtStt;
+
+int
+load_txt(FILE *fp)
+{
+    char line[MAXINPUTLINE];
+    char track_key[] = "TRK0";
+    char *track_dig = track_key + 3;
+    TxtStt state = NTRK;
+    char *sep, *nl, *cell;
+    int track, index, voice;
+    unsigned char pitch;
+    while (fgets(line, MAXINPUTLINE, fp)) {
+        if (line[0] == '\n')
+            continue;
+        switch (state) {
+        case NTRK:
+            if (strncmp(line, "ntracks:", 8))
+                return -1;
+            ntracks = atoi(line + 8);
+            track = 0;
+            state = MTDT;
+            break;
+        case MTDT:
+            if ((sep = strchr(line, ':'))) {
+                nl = strchr(line, '\n');
+                *sep = *nl = '\0';
+                map_put(line, sep + 1);
+                break;
+            } else {
+                state = TKNM;
+            }
+            /* fall through */
+        case TKNM:
+            state = EVNT;
+track_name:
+            nl = strchr(line, '\n');
+            *nl = '\0';
+            map_put(track_key, line);
+            *track_dig = *track_dig == '9' ? 'A' : *track_dig + 1;
+            index = 0;
+            break;
+        case EVNT:
+            if (isdigit(line[0])) {
+                /* noteset */
+                cell = &line[2];
+                voice = 0;
+                while (*cell) {
+                    switch (*cell) {
+                    case '.':
+                        /* matrix[track][index][voice] = REST; */
+                        break;
+                    case '=':
+                        matrix[track][index][voice] = CONT;
+                        break;
+                    default:
+                        pitch = (cell[0] - '0') * 10 + cell[1] - '0';
+                        matrix[track][index][voice] = pitch | 0x80;
+                    }
+                    cell += 3;
+                    voice++;
+                }
+                index++;
+            } else {
+                if (!strchr(line, ':')) {
+                    matrix[track][index][0] = END;
+                    track++;
+                    goto track_name;
+                }
+                printf("ignoring metaevent: %s", line);
+            }
+        }
+    }
+    matrix[track][index][0] = END;
+    ntracks = track + 1;
+    return 0;
+}
+
+int
+save_txt(FILE *fp)
+{
+    int track, index, voice;
+    int last_voice;
+    unsigned char cell;
+    char track_key[] = "TRK0";
+    char *track_dig = track_key + 3;
+    fprintf(fp, "ntracks:%d\n\n", ntracks);
+    /* TODO: write metadata */
+    fprintf(fp, "foo:bar\n");
+    for (track = 0; track < ntracks; track++) {
+        fprintf(fp, "\n%s\n\n", map_get(track_key));
+        for (index = 0; index < MAXINDEX; index++) {
+            if (matrix[track][index][0] == END)
+                break;
+            for (voice = MAXVOICE-1; voice >= 0; voice--)
+                if (matrix[track][index][voice])
+                    break;
+            last_voice = voice;
+            for (voice = 0; voice <= last_voice; voice++) {
+                cell = matrix[track][index][voice];
+                if (cell & 0x80)
+                    fprintf(fp, " %2u", cell & 0x7F);
+                else if (cell == REST)
+                    fprintf(fp, " ..");
+                else if (cell == CONT)
+                    fprintf(fp, " ==");
+                else
+                    fprintf(fp, " ??");
+            }
+            fprintf(fp, "\n");
+        }
+        *track_dig = *track_dig == '9' ? 'A' : *track_dig + 1;
+    }
+    return 0;
+}
+
+int
+main()
+{
+    if (load_txt(stdin) < 0)
+        return -1;
+    if (save_txt(stdout) < 0)
+        return -2;
+    return 0;
+}