1 /************************************************************************
2 * seq2mid.c - converts dump of /dev/sequencer (aka toy.c ouput) to a
3 * type 0 midi file.
4 *
5 * This code was written by by Nathan Laredo (laredo@gnu.ai.mit.edu)
6 * Source code may be freely distributed in unmodified form.
7 *************************************************************************/
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <sys/soundcard.h>
13
14 int outfile, infile;
15
16 /*
17 * midi header, track header, and timing info. Given timing is good for
18 * /dev/sequencer tick of 100Hz. Adjust division for others.
19 */
20
21 #define FLUFFSIZE 29
22 unsigned char midifluff[FLUFFSIZE] =
23 { 0x4d, 0x54, 0x68, 0x64, /* MThd */
24 0x00, 0x00, 0x00, 0x06, /* 6 bytes in header block */
25 0x00, 0x00, /* midi format 0 */
26 0x00, 0x01, /* one track */
27 /* the following line is for a 100Hz sequencer tick, adjust accordingly */
28 0x00, 0x32, /* 50 ticks per quarter, 100Hz resolution */
29 0x4d, 0x54, 0x72, 0x6b, /* MTrk */
30 #define SIZEINDEX 18
31 0x00, 0x00, 0x00, 0x00, /* x bytes in track block */
32 0x00, 0xff, 0x51, 0x03, /* meta tempo event */
33 0x07, 0xA1, 0x20 /* one quarter note = .5 sec = 120bpm */
34 #define STARTCOUNT 7
35 };
36
37 #define ENDFLUFFSIZE 4
38 unsigned char endfluff[ENDFLUFFSIZE] =
39 { 0x00, 0xff, 0x2f, 0x00 }; /* meta end of track */
40
41 /* indexed by high nibble of command */
42 int cmdlen[16] =
43 {0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0};
44
midiwrite(buf,count)45 void midiwrite(buf, count)
46 unsigned char *buf;
47 int count;
48 {
49 if(write(outfile, buf, count) < count) {
50 perror("write");
51 exit(-1);
52 }
53 }
54
main(argc,argv)55 int main(argc, argv)
56 int argc;
57 char **argv;
58 {
59 unsigned char delta[4], inputbuf[5], mid[8], cmd = 0;
60 unsigned int oldticks = 0, ticks = 0, db = 0;
61 off_t filesize, tracksize;
62 int i, status = 0;
63
64 if (argc < 3) {
65 fprintf(stderr, "usage: %s infile.seq outfile.mid\n", argv[0]);
66 exit(1);
67 }
68 if ((infile = open(argv[1], O_RDONLY, 0)) < 0) {
69 perror(argv[1]);
70 exit(-1);
71 }
72 if ((outfile = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666))
73 < 0) {
74 perror(argv[2]);
75 exit(-1);
76 }
77 midiwrite(midifluff, FLUFFSIZE);
78 inputbuf[4] = 0;
79 while (read(infile, inputbuf, 4) == 4) {
80 if (inputbuf[0] == SEQ_WAIT)
81 ticks = (*(unsigned int *) &inputbuf[1]);
82 if (*inputbuf == SEQ_MIDIPUTC) {
83 if (inputbuf[1] & 0x80)
84 cmd = mid[db = 0] = inputbuf[1];
85 else
86 mid[db] = inputbuf[1];
87 db++;
88 if (db == cmdlen[cmd >> 4] + 1) {
89 register unsigned int buffer = ticks - oldticks;
90 delta[i = 3] = (buffer & 0x7f);
91 while ((buffer >>= 7) > 0 && i > 0)
92 delta[--i] = (buffer & 0x7f) | 0x80;
93 midiwrite(&delta[i], 4 - i);
94 if (status == cmd && cmd < 0xf0)
95 midiwrite(&mid[1], db - 1);
96 else
97 midiwrite(mid, db);
98 status = mid[0];
99 oldticks = ticks;
100 db = 1;
101 }
102 }
103 }
104 midiwrite(endfluff, ENDFLUFFSIZE);
105
106 /* write big endian track size */
107 filesize = lseek(outfile, 0, SEEK_CUR);
108 tracksize = filesize - FLUFFSIZE + STARTCOUNT;
109 lseek(outfile, SIZEINDEX, SEEK_SET);
110 delta[0] = (tracksize >> 24) & 0xff;
111 delta[1] = (tracksize >> 16) & 0xff;
112 delta[2] = (tracksize >> 8) & 0xff;
113 delta[3] = tracksize & 0xff;
114 midiwrite(delta, 4);
115 close(infile);
116 close(outfile);
117 printf("%s: saved as %s, %d bytes, %d bytes track data\n",
118 argv[1], argv[2], (int) filesize, (int) tracksize);
119 exit(0);
120 }
121 /* end of file */
122